From c42f151716626bb21bd93ab2e9fca8cfe12f8cf0 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 31 Jul 2016 23:01:13 +0200 Subject: [PATCH 01/40] [C++] Added Mandelbrot, Bounce, Permute, Queens, Sieve, Storage, Towers - added clang-tidy settings --- benchmarks/C++/.clang-format | 259 ++++++++++++++++++++++++++++++++ benchmarks/C++/.clang-tidy | 28 ++++ benchmarks/C++/build.sh | 26 ++++ benchmarks/C++/src/benchmark.h | 18 +++ benchmarks/C++/src/bounce.h | 86 +++++++++++ benchmarks/C++/src/harness.cpp | 41 +++++ benchmarks/C++/src/mandelbrot.h | 91 +++++++++++ benchmarks/C++/src/permute.h | 41 +++++ benchmarks/C++/src/queens.h | 75 +++++++++ benchmarks/C++/src/run.h | 108 +++++++++++++ benchmarks/C++/src/sieve.h | 38 +++++ benchmarks/C++/src/som/random.h | 15 ++ benchmarks/C++/src/storage.h | 50 ++++++ benchmarks/C++/src/towers.h | 97 ++++++++++++ 14 files changed, 973 insertions(+) create mode 100644 benchmarks/C++/.clang-format create mode 100644 benchmarks/C++/.clang-tidy create mode 100755 benchmarks/C++/build.sh create mode 100644 benchmarks/C++/src/benchmark.h create mode 100644 benchmarks/C++/src/bounce.h create mode 100644 benchmarks/C++/src/harness.cpp create mode 100644 benchmarks/C++/src/mandelbrot.h create mode 100644 benchmarks/C++/src/permute.h create mode 100644 benchmarks/C++/src/queens.h create mode 100644 benchmarks/C++/src/run.h create mode 100644 benchmarks/C++/src/sieve.h create mode 100644 benchmarks/C++/src/som/random.h create mode 100644 benchmarks/C++/src/storage.h create mode 100644 benchmarks/C++/src/towers.h diff --git a/benchmarks/C++/.clang-format b/benchmarks/C++/.clang-format new file mode 100644 index 00000000..75121a6b --- /dev/null +++ b/benchmarks/C++/.clang-format @@ -0,0 +1,259 @@ +--- +Language: Cpp +# BasedOnStyle: Chromium +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: false +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAfterAttributes: Never +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: "^ IWYU pragma:" +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*\.h>' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: "^<.*" + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: ".*" + Priority: 3 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: "([-_](test|unittest))?$" +IncludeIsMainSourceRegex: "" +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: true +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: "" +MacroBlockEnd: "" +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: NextLine +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Leave +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - "c++" + - "C++" + CanonicalDelimiter: "" + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + CanonicalDelimiter: pb + BasedOnStyle: google +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +--- + diff --git a/benchmarks/C++/.clang-tidy b/benchmarks/C++/.clang-tidy new file mode 100644 index 00000000..e99465a6 --- /dev/null +++ b/benchmarks/C++/.clang-tidy @@ -0,0 +1,28 @@ +--- +Checks: '*,-modernize-use-trailing-return-type,-altera-unroll-loops,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-llvm-header-guard,-llvmlibc-*,-misc-no-recursion,-concurrency-mt-unsafe,-readability-identifier-length,-misc-use-anonymous-namespace,-readability-convert-member-functions-to-static,-bugprone-easily-swappable-parameters,-fuchsia-default-arguments-calls,-hicpp-named-parameter,-readability-named-parameter,-altera-id-dependent-backward-branch,-readability-delete-null-pointer,-cppcoreguidelines-avoid-const-or-ref-data-members,-cppcoreguidelines-pro-bounds-constant-array-index' +WarningsAsErrors: '' +HeaderFilterRegex: '' +AnalyzeTemporaryDtors: false +FormatStyle: none +User: smarr +CheckOptions: + llvm-else-after-return.WarnOnConditionVariables: 'false' + modernize-loop-convert.MinConfidence: reasonable + modernize-replace-auto-ptr.IncludeStyle: llvm + cert-str34-c.DiagnoseSignedUnsignedCharComparisons: 'false' + google-readability-namespace-comments.SpacesBeforeComments: '2' + cert-err33-c.CheckedFunctions: '::aligned_alloc;::asctime_s;::at_quick_exit;::atexit;::bsearch;::bsearch_s;::btowc;::c16rtomb;::c32rtomb;::calloc;::clock;::cnd_broadcast;::cnd_init;::cnd_signal;::cnd_timedwait;::cnd_wait;::ctime_s;::fclose;::fflush;::fgetc;::fgetpos;::fgets;::fgetwc;::fopen;::fopen_s;::fprintf;::fprintf_s;::fputc;::fputs;::fputwc;::fputws;::fread;::freopen;::freopen_s;::fscanf;::fscanf_s;::fseek;::fsetpos;::ftell;::fwprintf;::fwprintf_s;::fwrite;::fwscanf;::fwscanf_s;::getc;::getchar;::getenv;::getenv_s;::gets_s;::getwc;::getwchar;::gmtime;::gmtime_s;::localtime;::localtime_s;::malloc;::mbrtoc16;::mbrtoc32;::mbsrtowcs;::mbsrtowcs_s;::mbstowcs;::mbstowcs_s;::memchr;::mktime;::mtx_init;::mtx_lock;::mtx_timedlock;::mtx_trylock;::mtx_unlock;::printf_s;::putc;::putwc;::raise;::realloc;::remove;::rename;::scanf;::scanf_s;::setlocale;::setvbuf;::signal;::snprintf;::snprintf_s;::sprintf;::sprintf_s;::sscanf;::sscanf_s;::strchr;::strerror_s;::strftime;::strpbrk;::strrchr;::strstr;::strtod;::strtof;::strtoimax;::strtok;::strtok_s;::strtol;::strtold;::strtoll;::strtoul;::strtoull;::strtoumax;::strxfrm;::swprintf;::swprintf_s;::swscanf;::swscanf_s;::thrd_create;::thrd_detach;::thrd_join;::thrd_sleep;::time;::timespec_get;::tmpfile;::tmpfile_s;::tmpnam;::tmpnam_s;::tss_create;::tss_get;::tss_set;::ungetc;::ungetwc;::vfprintf;::vfprintf_s;::vfscanf;::vfscanf_s;::vfwprintf;::vfwprintf_s;::vfwscanf;::vfwscanf_s;::vprintf_s;::vscanf;::vscanf_s;::vsnprintf;::vsnprintf_s;::vsprintf;::vsprintf_s;::vsscanf;::vsscanf_s;::vswprintf;::vswprintf_s;::vswscanf;::vswscanf_s;::vwprintf_s;::vwscanf;::vwscanf_s;::wcrtomb;::wcschr;::wcsftime;::wcspbrk;::wcsrchr;::wcsrtombs;::wcsrtombs_s;::wcsstr;::wcstod;::wcstof;::wcstoimax;::wcstok;::wcstok_s;::wcstol;::wcstold;::wcstoll;::wcstombs;::wcstombs_s;::wcstoul;::wcstoull;::wcstoumax;::wcsxfrm;::wctob;::wctrans;::wctype;::wmemchr;::wprintf_s;::wscanf;::wscanf_s;' + cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField: 'false' + cert-dcl16-c.NewSuffixes: 'L;LL;LU;LLU' + google-readability-braces-around-statements.ShortStatementLines: '1' + modernize-pass-by-value.IncludeStyle: llvm + google-readability-namespace-comments.ShortNamespaceLines: '10' + modernize-loop-convert.MaxCopySize: '16' + modernize-use-nullptr.NullMacros: 'NULL' + llvm-qualified-auto.AddConstToQualified: 'false' + cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic: 'true' + modernize-loop-convert.NamingStyle: CamelCase + llvm-else-after-return.WarnOnUnfixable: 'false' + google-readability-function-size.StatementThreshold: '800' +... + diff --git a/benchmarks/C++/build.sh b/benchmarks/C++/build.sh new file mode 100755 index 00000000..923f082f --- /dev/null +++ b/benchmarks/C++/build.sh @@ -0,0 +1,26 @@ +#!/bin/bash +if [ "$1" = "format" ] +then + CMD=clang-format + type -P "$CMD" || CMD=clang-format-mp-16 + $CMD -i --style=file src/*.cpp src/*.h + exit 0 +fi + +if [ "$1" = "check-format" ] +then + CMD=clang-format + type -P "$CMD" || CMD=clang-format-mp-16 + $CMD --style=file --dry-run --Werror src/*.cpp src/*.h + exit 0 +fi + +if [ "$1" = "lint" ] +then + CMD=clang-tidy + type -P "$CMD" || CMD=clang-tidy-mp-16 + $CMD --config-file=.clang-tidy -header-filter=.* src/*.cpp + exit 0 +fi + +clang++-mp-16 -Wall -Wextra -O2 -ffp-contract=off -std=c++17 src/harness.cpp -o harness diff --git a/benchmarks/C++/src/benchmark.h b/benchmarks/C++/src/benchmark.h new file mode 100644 index 00000000..71be1860 --- /dev/null +++ b/benchmarks/C++/src/benchmark.h @@ -0,0 +1,18 @@ +#pragma once + +class Benchmark { + public: + virtual ~Benchmark() = default; + + virtual void* benchmark() = 0; + virtual bool verify_result(void* result) = 0; + + virtual bool inner_benchmark_loop(int32_t inner_iterations) { + for (int32_t i = 0; i < inner_iterations; i++) { + if (!verify_result(benchmark())) { + return false; + } + } + return true; + } +}; diff --git a/benchmarks/C++/src/bounce.h b/benchmarks/C++/src/bounce.h new file mode 100644 index 00000000..98c4b3f3 --- /dev/null +++ b/benchmarks/C++/src/bounce.h @@ -0,0 +1,86 @@ +#pragma once + +#include "benchmark.h" +#include "som/random.h" + +class Ball { + private: + int32_t x; + int32_t y; + int32_t x_vel; + int32_t y_vel; + + public: + Ball() = default; + + Ball(Ball&&) = default; + + ~Ball() = default; + + explicit Ball(Random& random) + : x(random.next() % 500), + y(random.next() % 500), + x_vel((random.next() % 300) - 150), + y_vel((random.next() % 300) - 150) {} + + Ball& operator=(const Ball&) = default; + + bool bounce() { + const int32_t x_limit = 500; + const int32_t y_limit = 500; + bool bounced = false; + + x += x_vel; + y += y_vel; + if (x > x_limit) { + x = x_limit; + x_vel = 0 - abs(x_vel); + bounced = true; + } + if (x < 0) { + x = 0; + x_vel = abs(x_vel); + bounced = true; + } + if (y > y_limit) { + y = y_limit; + y_vel = 0 - abs(y_vel); + bounced = true; + } + if (y < 0) { + y = 0; + y_vel = abs(y_vel); + bounced = true; + } + return bounced; + } +}; + +class Bounce : public Benchmark { + public: + void* benchmark() override { + Random random; + + const int32_t ball_count = 100; + int32_t bounces = 0; + + std::array balls = {}; + + for (auto& ball : balls) { + ball = Ball(random); + } + + for (int32_t j = 0; j < 50; j++) { + for (auto& ball : balls) { + if (ball.bounce()) { + bounces++; + } + } + } + return reinterpret_cast(static_cast(bounces)); + } + + bool verify_result(void* result) override { + return 1331 == static_cast(reinterpret_cast(result)); + } +}; diff --git a/benchmarks/C++/src/harness.cpp b/benchmarks/C++/src/harness.cpp new file mode 100644 index 00000000..36af6a19 --- /dev/null +++ b/benchmarks/C++/src/harness.cpp @@ -0,0 +1,41 @@ +#include + +#include "run.h" + +static Run process_arguments(int32_t argc, const char* argv[]) { // NOLINT + std::string name(argv[1]); + Run run(name); + + if (argc > 2) { + run.set_num_iterations(std::stoi(argv[2])); + if (argc > 3) { + run.set_inner_iterations(std::stoi(argv[3])); + } + } + + return run; +} + +static void print_usage() { + std::cout << "./harness benchmark [num-iterations [inner-iter]]\n"; + std::cout << "\n"; + std::cout << " benchmark - benchmark class name\n"; + std::cout << " num-iterations - number of times to execute benchmark, " + "default: 1\n"; + std::cout << " inner-iter - number of times the benchmark is executed " + "in an inner loop,\n"; + std::cout << " which is measured in total, default: 1\n"; +} + +int main(int argc, const char* argv[]) { + if (argc < 2) { + print_usage(); + return 1; + } + + Run run = process_arguments(argc, argv); + run.run_benchmark(); + run.print_total(); + + return 0; +} diff --git a/benchmarks/C++/src/mandelbrot.h b/benchmarks/C++/src/mandelbrot.h new file mode 100644 index 00000000..a2a7fa3c --- /dev/null +++ b/benchmarks/C++/src/mandelbrot.h @@ -0,0 +1,91 @@ +#pragma once + +#include + +#include "benchmark.h" + +class Mandelbrot : public Benchmark { + public: + void* benchmark() override { return nullptr; }; + bool verify_result(void*) override { return false; }; + + bool inner_benchmark_loop(int32_t inner_iterations) override { + return verify_result(mandelbrot(inner_iterations), inner_iterations); + } + + private: + bool verify_result(int32_t result, int32_t inner_iterations) { + if (inner_iterations == 500) { + return result == 191; + } + if (inner_iterations == 750) { + return result == 50; + } + if (inner_iterations == 1) { + return result == 128; + } + + std::cout << "No verification result for " << inner_iterations + << " found\n"; + std::cout << "Result is: " << result << "\n"; + return false; + } + + int32_t mandelbrot(int32_t size) { + int32_t sum = 0; + int32_t byte_acc = 0; + int32_t bit_num = 0; + + int32_t y = 0; + + while (y < size) { + const double ci = (2.0 * y / size) - 1.0; + int32_t x = 0; + + while (x < size) { + double zrzr = 0.0; + double zi = 0.0; + double zizi = 0.0; + const double cr = (2.0 * x / size) - 1.5; + + int32_t z = 0; + bool notDone = true; + int32_t escape = 0; + while (notDone && z < 50) { + const double zr = zrzr - zizi + cr; + zi = 2.0 * zr * zi + ci; + + // preserve recalculation + zrzr = zr * zr; + zizi = zi * zi; + + if (zrzr + zizi > 4.0) { + notDone = false; + escape = 1; + } + z += 1; + } + + byte_acc = (byte_acc << 1) + escape; + bit_num += 1; + + // Code is very similar for these cases, but using separate blocks + // ensures we skip the shifting when it's unnecessary, which is most + // cases. + if (bit_num == 8) { + sum ^= byte_acc; + byte_acc = 0; + bit_num = 0; + } else if (x == size - 1) { + byte_acc <<= (8 - bit_num); + sum ^= byte_acc; + byte_acc = 0; + bit_num = 0; + } + x += 1; + } + y += 1; + } + return sum; + } +}; diff --git a/benchmarks/C++/src/permute.h b/benchmarks/C++/src/permute.h new file mode 100644 index 00000000..50cea10d --- /dev/null +++ b/benchmarks/C++/src/permute.h @@ -0,0 +1,41 @@ +#pragma once + +#include "benchmark.h" + +class Permute : public Benchmark { + private: + int32_t count{0}; + int32_t* v{nullptr}; + + void permute(int32_t n) { + count++; + if (n != 0) { + const int32_t n1 = n - 1; + permute(n1); + for (int32_t i = n1; i >= 0; i--) { + swap(n1, i); + permute(n1); + swap(n1, i); + } + } + } + + void swap(int32_t i, int32_t j) { + const int32_t tmp = v[i]; + v[i] = v[j]; + v[j] = tmp; + } + + public: + void* benchmark() override { + count = 0; + v = new int32_t[6]; + permute(6); + delete[] v; + return reinterpret_cast(static_cast(count)); + } + + bool verify_result(void* result) override { + return 8660 == static_cast(reinterpret_cast(result)); + } +}; diff --git a/benchmarks/C++/src/queens.h b/benchmarks/C++/src/queens.h new file mode 100644 index 00000000..ae72ad49 --- /dev/null +++ b/benchmarks/C++/src/queens.h @@ -0,0 +1,75 @@ +#pragma once + +#include + +#include "benchmark.h" + +class Queens : public Benchmark { + private: + bool* free_maxs{nullptr}; + bool* free_rows{nullptr}; + bool* free_mins{nullptr}; + int32_t* queen_rows{nullptr}; + + bool queens() { + free_rows = new bool[8]; + std::fill_n(free_rows, 8, true); + free_maxs = new bool[16]; + std::fill_n(free_maxs, 16, true); + free_mins = new bool[16]; + std::fill_n(free_mins, 16, true); + queen_rows = new int32_t[8]; + std::fill_n(queen_rows, 8, -1); + + const bool result = place_queen(0); + + delete[] free_rows; + delete[] free_maxs; + delete[] free_mins; + delete[] queen_rows; + + return result; + } + + bool place_queen(int32_t c) { + for (int32_t r = 0; r < 8; r++) { + if (get_row_column(r, c)) { + queen_rows[r] = c; + set_row_column(r, c, false); + + if (c == 7) { + return true; + } + + if (place_queen(c + 1)) { + return true; + } + set_row_column(r, c, true); + } + } + return false; + } + + bool get_row_column(int32_t r, int32_t c) { + return free_rows[r] && free_maxs[c + r] && free_mins[c - r + 7]; + } + + void set_row_column(int32_t r, int32_t c, bool v) { + free_rows[r] = v; + free_maxs[c + r] = v; + free_mins[c - r + 7] = v; + } + + public: + void* benchmark() override { + bool result = true; + for (int32_t i = 0; i < 10; i++) { + result = result && queens(); + } + return reinterpret_cast(result); + } + + bool verify_result(void* result) override { + return static_cast(reinterpret_cast(result)); + } +}; diff --git a/benchmarks/C++/src/run.h b/benchmarks/C++/src/run.h new file mode 100644 index 00000000..7074884d --- /dev/null +++ b/benchmarks/C++/src/run.h @@ -0,0 +1,108 @@ +#pragma once + +#include +#include + +#include "bounce.h" +#include "mandelbrot.h" +#include "permute.h" +#include "queens.h" +#include "sieve.h" +#include "storage.h" +#include "towers.h" + +using benchmark_suite_ctr = Benchmark* (*)(); + +class Run { + private: + const std::string name; + benchmark_suite_ctr suite; + int32_t num_iterations{1}; + int32_t inner_iterations{1}; + int64_t total{0}; + + public: + explicit Run(std::string& name) : name(name), suite(select_benchmark(name)) {} + + void run_benchmark() { + std::cout << "Starting " << name << " benchmark ...\n"; + Benchmark* benchmark = suite(); + do_runs(benchmark); + delete benchmark; + + report_benchmark(); + std::cout << "\n"; + } + + void print_total() const { + std::cout << "Total Runtime: " << total << "us\n"; + } + + void set_num_iterations(int32_t num_iterations) { + this->num_iterations = num_iterations; + } + + void set_inner_iterations(int32_t inner_iterations) { + this->inner_iterations = inner_iterations; + } + + private: + benchmark_suite_ctr select_benchmark(std::string& name) { + if (name == "Bounce") { + return []() -> Benchmark* { return new Bounce(); }; + } + if (name == "Mandelbrot") { + return []() -> Benchmark* { return new Mandelbrot(); }; + } + if (name == "Permute") { + return []() -> Benchmark* { return new Permute(); }; + } + if (name == "Queens") { + return []() -> Benchmark* { return new Queens(); }; + } + if (name == "Sieve") { + return []() -> Benchmark* { return new Sieve(); }; + } + if (name == "Storage") { + return []() -> Benchmark* { return new Storage(); }; + } + if (name == "Towers") { + return []() -> Benchmark* { return new Towers(); }; + } + + std::cerr << "Benchmark not recognized: " << name << "\n"; + exit(1); + } + + void measure(Benchmark* const bench) { + auto start_time = std::chrono::high_resolution_clock::now(); + if (!bench->inner_benchmark_loop(inner_iterations)) { + std::cout << "Benchmark failed with incorrect result\n"; + exit(1); // TODO: should this be an exception? + } + auto end_time = std::chrono::high_resolution_clock::now(); + const int64_t run_time = + std::chrono::duration_cast(end_time - + start_time) + .count(); + + print_result(run_time); + total += run_time; + } + + void do_runs(Benchmark* const bench) { + for (int32_t i = 0; i < num_iterations; i++) { + measure(bench); + } + } + + void report_benchmark() { + std::cout << name << ": iterations=" << num_iterations + << " average: " << (total / num_iterations) + << "us total: " << total << "us\n"; + } + + void print_result(int64_t run_time) { + std::cout << name << ": iterations=1 runtime: " << run_time << "us\n"; + } +}; diff --git a/benchmarks/C++/src/sieve.h b/benchmarks/C++/src/sieve.h new file mode 100644 index 00000000..3d715c7a --- /dev/null +++ b/benchmarks/C++/src/sieve.h @@ -0,0 +1,38 @@ +#pragma once + +#include "benchmark.h" + +class Sieve : public Benchmark { + public: + void* benchmark() override { + const int32_t num_flags = 5000; + std::array flags{}; + + std::fill_n(flags.begin(), num_flags, true); + + return reinterpret_cast( + static_cast(sieve(flags, 5000))); + } + + bool verify_result(void* result) override { + return 669 == static_cast(reinterpret_cast(result)); + } + + private: + template + int32_t sieve(std::array flags, int32_t size) { + int32_t prime_count = 0; + + for (int32_t i = 2; i <= size; i++) { + if (flags[i - 1]) { + prime_count++; + int k = i + i; + while (k <= size) { + flags[k - 1] = false; + k += i; + } + } + } + return prime_count; + } +}; diff --git a/benchmarks/C++/src/som/random.h b/benchmarks/C++/src/som/random.h new file mode 100644 index 00000000..1c762698 --- /dev/null +++ b/benchmarks/C++/src/som/random.h @@ -0,0 +1,15 @@ +#pragma once + +class Random { +private: + int32_t seed {74755}; + +public: + + Random() = default; + + int32_t next() { + seed = ((seed * 1309) + 13849) & 65535; + return seed; + } +}; diff --git a/benchmarks/C++/src/storage.h b/benchmarks/C++/src/storage.h new file mode 100644 index 00000000..038885c0 --- /dev/null +++ b/benchmarks/C++/src/storage.h @@ -0,0 +1,50 @@ +#pragma once + +#include + +#include "benchmark.h" +#include "som/random.h" + +class ArrayTree { + public: + ArrayTree* children{nullptr}; + + ArrayTree() = default; + ~ArrayTree() { delete[] children; } +}; + +class Storage : public Benchmark { + private: + int32_t count{0}; + + public: + Storage() = default; + + void* benchmark() override { + Random random; + + count = 0; + ArrayTree* result = build_tree_depth(7, random); + delete[] result; + + return reinterpret_cast(static_cast(count)); + } + + bool verify_result(void* result) override { + return 5461 == static_cast(reinterpret_cast(result)); + } + + private: + ArrayTree* build_tree_depth(int32_t depth, Random& random) { + count++; + if (depth == 1) { + return new ArrayTree[random.next() % 10 + 1]; + } + + ArrayTree* arr = new ArrayTree[4]; + for (size_t i = 0; i < 4; i++) { + arr[i].children = build_tree_depth(depth - 1, random); + } + return arr; + } +}; diff --git a/benchmarks/C++/src/towers.h b/benchmarks/C++/src/towers.h new file mode 100644 index 00000000..8ff1c68f --- /dev/null +++ b/benchmarks/C++/src/towers.h @@ -0,0 +1,97 @@ +#pragma once + +#include +#include + +#include "benchmark.h" + +class TowersDisk { + private: + const int32_t size; + TowersDisk* next{nullptr}; + + public: + explicit TowersDisk(int32_t size) : size(size) {} + + ~TowersDisk() { + if (next != nullptr) { + delete next; + } + } + + [[nodiscard]] int32_t get_size() const { return size; } + + [[nodiscard]] TowersDisk* get_next() const { return next; } + + void set_next(TowersDisk* disk) { next = disk; } +}; + +class Towers : public Benchmark { + private: + std::array piles{}; + int32_t moves_done{0}; + + public: + void* benchmark() override { + piles = std::array(); + build_tower_at(0, 13); + moves_done = 0; + move_disks(13, 0, 1); + + for (TowersDisk* disk : piles) { + delete disk; + } + + return reinterpret_cast(static_cast(moves_done)); + } + + bool verify_result(void* result) override { + return 8191 == static_cast(reinterpret_cast(result)); + } + + private: + void push_disk(TowersDisk* disk, int32_t pile) { + TowersDisk* top = piles.at(pile); + if (!(top == nullptr) && (disk->get_size() >= top->get_size())) { + std::cerr << "Cannot put a big disk on a smaller one"; + exit(1); + } + + disk->set_next(top); + piles.at(pile) = disk; + } + + TowersDisk* pop_disk_from(int32_t pile) { + TowersDisk* top = piles.at(pile); + if (top == nullptr) { + std::cerr << "Attempting to remove a disk from an empty pile"; + exit(1); + } + + piles.at(pile) = top->get_next(); + top->set_next(nullptr); + return top; + } + + void move_top_disk(int32_t from_pile, int32_t to_pile) { + push_disk(pop_disk_from(from_pile), to_pile); + moves_done++; + } + + void build_tower_at(int32_t pile, int32_t disks) { + for (int32_t i = disks; i >= 0; i--) { + push_disk(new TowersDisk(i), pile); + } + } + + void move_disks(int32_t disks, int32_t from_pile, int32_t to_pile) { + if (disks == 1) { + move_top_disk(from_pile, to_pile); + } else { + const int32_t other_pile = (3 - from_pile) - to_pile; + move_disks(disks - 1, from_pile, other_pile); + move_top_disk(from_pile, to_pile); + move_disks(disks - 1, other_pile, to_pile); + } + } +}; From 05e85f163b69b58285b2b580d209ef74ccbcbde7 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 24 Sep 2023 16:47:10 +0100 Subject: [PATCH 02/40] [C++] Added DeltaBlue and som library port by Hugo Jenningros --- .../C++/src/deltablue/AbstractConstraint.cpp | 67 +++++ .../C++/src/deltablue/AbstractConstraint.h | 48 ++++ .../C++/src/deltablue/BinaryConstraint.cpp | 110 ++++++++ .../C++/src/deltablue/BinaryConstraint.h | 28 ++ benchmarks/C++/src/deltablue/Direction.h | 10 + .../C++/src/deltablue/EditConstraint.cpp | 15 + benchmarks/C++/src/deltablue/EditConstraint.h | 22 ++ .../C++/src/deltablue/EqualityConstraint.cpp | 16 ++ .../C++/src/deltablue/EqualityConstraint.h | 20 ++ benchmarks/C++/src/deltablue/Plan.cpp | 14 + benchmarks/C++/src/deltablue/Plan.h | 19 ++ benchmarks/C++/src/deltablue/Planner.cpp | 230 ++++++++++++++++ benchmarks/C++/src/deltablue/Planner.h | 46 ++++ .../C++/src/deltablue/ScaleConstraint.cpp | 76 +++++ .../C++/src/deltablue/ScaleConstraint.h | 31 +++ .../C++/src/deltablue/StayConstraint.cpp | 11 + benchmarks/C++/src/deltablue/StayConstraint.h | 22 ++ benchmarks/C++/src/deltablue/Strength.cpp | 103 +++++++ benchmarks/C++/src/deltablue/Strength.h | 68 +++++ .../C++/src/deltablue/UnaryConstraint.cpp | 60 ++++ .../C++/src/deltablue/UnaryConstraint.h | 32 +++ benchmarks/C++/src/deltablue/Variable.cpp | 77 ++++++ benchmarks/C++/src/deltablue/Variable.h | 44 +++ benchmarks/C++/src/som/Dictionary.cpp | 259 ++++++++++++++++++ benchmarks/C++/src/som/Error.cpp | 27 ++ benchmarks/C++/src/som/IdentityDictionary.cpp | 29 ++ benchmarks/C++/src/som/Vector.cpp | 240 ++++++++++++++++ 27 files changed, 1724 insertions(+) create mode 100644 benchmarks/C++/src/deltablue/AbstractConstraint.cpp create mode 100644 benchmarks/C++/src/deltablue/AbstractConstraint.h create mode 100644 benchmarks/C++/src/deltablue/BinaryConstraint.cpp create mode 100644 benchmarks/C++/src/deltablue/BinaryConstraint.h create mode 100644 benchmarks/C++/src/deltablue/Direction.h create mode 100644 benchmarks/C++/src/deltablue/EditConstraint.cpp create mode 100644 benchmarks/C++/src/deltablue/EditConstraint.h create mode 100644 benchmarks/C++/src/deltablue/EqualityConstraint.cpp create mode 100644 benchmarks/C++/src/deltablue/EqualityConstraint.h create mode 100644 benchmarks/C++/src/deltablue/Plan.cpp create mode 100644 benchmarks/C++/src/deltablue/Plan.h create mode 100644 benchmarks/C++/src/deltablue/Planner.cpp create mode 100644 benchmarks/C++/src/deltablue/Planner.h create mode 100644 benchmarks/C++/src/deltablue/ScaleConstraint.cpp create mode 100644 benchmarks/C++/src/deltablue/ScaleConstraint.h create mode 100644 benchmarks/C++/src/deltablue/StayConstraint.cpp create mode 100644 benchmarks/C++/src/deltablue/StayConstraint.h create mode 100644 benchmarks/C++/src/deltablue/Strength.cpp create mode 100644 benchmarks/C++/src/deltablue/Strength.h create mode 100644 benchmarks/C++/src/deltablue/UnaryConstraint.cpp create mode 100644 benchmarks/C++/src/deltablue/UnaryConstraint.h create mode 100644 benchmarks/C++/src/deltablue/Variable.cpp create mode 100644 benchmarks/C++/src/deltablue/Variable.h create mode 100644 benchmarks/C++/src/som/Dictionary.cpp create mode 100644 benchmarks/C++/src/som/Error.cpp create mode 100644 benchmarks/C++/src/som/IdentityDictionary.cpp create mode 100644 benchmarks/C++/src/som/Vector.cpp diff --git a/benchmarks/C++/src/deltablue/AbstractConstraint.cpp b/benchmarks/C++/src/deltablue/AbstractConstraint.cpp new file mode 100644 index 00000000..3746f882 --- /dev/null +++ b/benchmarks/C++/src/deltablue/AbstractConstraint.cpp @@ -0,0 +1,67 @@ +#include "Planner.h" + +using namespace std; + +namespace deltablue { + + AbstractConstraint::AbstractConstraint(shared_ptr strength) { + _strength = Strength::of(strength); + } + + shared_ptr AbstractConstraint::getStrength() { + return _strength; + } + + bool AbstractConstraint::isInput() { + return false; + } + + void AbstractConstraint::addConstraint(shared_ptr planner) { + addToGraph(); + planner->incrementalAdd(shared_from_this()); + } + + + void AbstractConstraint::destroyConstraint(shared_ptr planner) { + if (isSatisfied()) { + planner->incrementalRemove(shared_from_this()); + } + removeFromGraph(); + } + + bool AbstractConstraint::inputsKnown(int mark) { + return !inputsHasOne([&mark](shared_ptr v) -> bool { + return !(v->getMark() == mark || v->getStay() || v->getDeterminedBy() == nullptr); + }); + } + + shared_ptr AbstractConstraint::satisfy(int mark, shared_ptr planner) { + shared_ptr overridden; + + chooseMethod(mark); + + if (isSatisfied()) { + + inputsDo([&mark](shared_ptr in) -> void { + in->setMark(mark); + }); + + shared_ptr out = getOutput(); + overridden = out->getDeterminedBy(); + if (overridden != nullptr) { + overridden->markUnsatisfied(); + } + out->setDeterminedBy(shared_from_this()); + if (!planner->addPropagate(shared_from_this(), mark)) { + throw Error("Cycle encountered"); + } + out->setMark(mark); + } else { + overridden = nullptr; + if (_strength->sameAs(Strength::required())) { + throw Error("Could not satisfy a required constraint"); + } + } + return overridden; + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/AbstractConstraint.h b/benchmarks/C++/src/deltablue/AbstractConstraint.h new file mode 100644 index 00000000..557b25b6 --- /dev/null +++ b/benchmarks/C++/src/deltablue/AbstractConstraint.h @@ -0,0 +1,48 @@ +#ifndef ABSTRACTCONSTRAINT +#define ABSTRACTCONSTRAINT + +#include +#include +#include +#include "../som/Error.cpp" +#include "Variable.h" +#include "Direction.h" + +using namespace std; + +namespace deltablue { + + class Planner; + + class AbstractConstraint : public enable_shared_from_this { + protected: + shared_ptr _strength; + shared_ptr _planer; + public: + + + AbstractConstraint(shared_ptr strength); + + shared_ptr getStrength(); + virtual bool isInput(); + void addConstraint(shared_ptr planner); + void destroyConstraint(shared_ptr planner); + bool inputsKnown(int mark); + shared_ptr satisfy(int mark, shared_ptr planner); + + virtual bool isSatisfied() {}; + virtual void addToGraph() {}; + virtual void removeFromGraph() {}; + virtual Direction chooseMethod(int mark) {}; + virtual void execute() {}; + virtual void inputsDo(function)> fn) {}; + virtual bool inputsHasOne(function )> fn) {}; + virtual void markUnsatisfied() {}; + virtual shared_ptr getOutput() {}; + virtual void recalculate() {}; + + + }; +} + +#endif //ABSTRACTCONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/BinaryConstraint.cpp b/benchmarks/C++/src/deltablue/BinaryConstraint.cpp new file mode 100644 index 00000000..75a7face --- /dev/null +++ b/benchmarks/C++/src/deltablue/BinaryConstraint.cpp @@ -0,0 +1,110 @@ +#include "BinaryConstraint.h" + +namespace deltablue { + + BinaryConstraint::BinaryConstraint(shared_ptr var1, shared_ptr var2, + shared_ptr strength/*, shared_ptr planner*/) : AbstractConstraint(strength) { /// don't use planner ??? Probleme with "this" + _v1 = var1; + _v2 = var2; + _direction = NONE; + } + + bool BinaryConstraint::isSatisfied() { + return _direction != NONE; + } + + void BinaryConstraint::addToGraph() { + _v1->addConstraint(shared_from_this()); + _v2->addConstraint(shared_from_this()); + _direction = NONE; + } + + void BinaryConstraint::removeFromGraph() { + _v1->removeConstraint(shared_from_this()); + _v2->removeConstraint(shared_from_this()); + _direction = NONE; + } + + Direction BinaryConstraint::chooseMethod(int mark) { + if (_v1->getMark() == mark) { + if (_v2->getMark() != mark && _strength->stronger(_v2->getWalkStrength())) { + _direction = FORWARD; + return _direction; + } else { + _direction = NONE; + return _direction; + } + } + + if (_v2->getMark() == mark) { + if (_v1->getMark() != mark && _strength->stronger(_v1->getWalkStrength())) { + _direction = BACKWARD; + return _direction; + } else { + _direction = NONE; + return _direction; + } + } + + if (_v1->getWalkStrength()->weaker(_v2->getWalkStrength())) { + if (_strength->stronger(_v1->getWalkStrength())) { + _direction = BACKWARD; + return _direction; + } else { + _direction = NONE; + return _direction; + } + } else { + if (_strength->stronger(_v2->getWalkStrength())) { + _direction = FORWARD; + return _direction; + } else { + _direction = NONE; + return _direction; + } + } + } + + void BinaryConstraint::inputsDo(function)> fn) { + if (_direction == FORWARD) { + fn(_v1); + } else { + fn(_v2); + } + } + + bool BinaryConstraint::inputsHasOne(function)> fn) { + if (_direction == FORWARD) { + return fn(_v1); + } else { + return fn(_v2); + } + } + + void BinaryConstraint::markUnsatisfied() { + _direction = NONE; + } + + shared_ptr BinaryConstraint::getOutput() { + return _direction == FORWARD ? _v2 : _v1; + } + + void BinaryConstraint::recalculate() { + shared_ptr in; + shared_ptr out; + + if (_direction == FORWARD) { + in = _v1; + out = _v2; + } else { + in = _v2; + out = _v1; + } + + out->setWalkStrength(_strength->weakest(in->getWalkStrength())); + out->setStay(in->getStay()); + if (out->getStay()) { + execute(); + } + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/BinaryConstraint.h b/benchmarks/C++/src/deltablue/BinaryConstraint.h new file mode 100644 index 00000000..23ad3ba4 --- /dev/null +++ b/benchmarks/C++/src/deltablue/BinaryConstraint.h @@ -0,0 +1,28 @@ +#ifndef BINARYCONSTRAINT +#define BINARYCONSTRAINT + +#include "AbstractConstraint.h" + +using namespace std; + +namespace deltablue { + class BinaryConstraint: public AbstractConstraint { + protected: + shared_ptr _v1; + shared_ptr _v2; + Direction _direction; + + public: + BinaryConstraint(shared_ptr var1, shared_ptr var2, shared_ptr strength/*, shared_ptr planner*/); + bool isSatisfied() override; + void addToGraph() override; + void removeFromGraph() override; + Direction chooseMethod(int mark) override; + void inputsDo(function)> fn) override; + bool inputsHasOne(function)> fn) override; + void markUnsatisfied() override; + shared_ptr getOutput() override; + void recalculate() override ; + }; +} +#endif //BINARYCONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Direction.h b/benchmarks/C++/src/deltablue/Direction.h new file mode 100644 index 00000000..9a72ac7d --- /dev/null +++ b/benchmarks/C++/src/deltablue/Direction.h @@ -0,0 +1,10 @@ +#ifndef DIRECTION +#define DIRECTION + +namespace deltablue { + enum Direction { + FORWARD, BACKWARD, NONE + }; +} + +#endif //DIRECTION \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/EditConstraint.cpp b/benchmarks/C++/src/deltablue/EditConstraint.cpp new file mode 100644 index 00000000..d8a0bf44 --- /dev/null +++ b/benchmarks/C++/src/deltablue/EditConstraint.cpp @@ -0,0 +1,15 @@ +#include "EditConstraint.h" + +namespace deltablue { + EditConstraint::EditConstraint(shared_ptr v, shared_ptr strength, shared_ptr planner) + : UnaryConstraint(v, strength, planner) { + } + + bool EditConstraint::isInput() { + return true; + } + + void EditConstraint::execute() { + // Edit constraints do nothing. + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/EditConstraint.h b/benchmarks/C++/src/deltablue/EditConstraint.h new file mode 100644 index 00000000..e3d57ef7 --- /dev/null +++ b/benchmarks/C++/src/deltablue/EditConstraint.h @@ -0,0 +1,22 @@ +#ifndef EDITCONSTRAINT +#define EDITCONSTRAINT + +#include +#include "Planner.h" +#include "UnaryConstraint.h" + +using namespace std; + +namespace deltablue { + + class EditConstraint: public UnaryConstraint { + public: + + EditConstraint(shared_ptr v, shared_ptr strength, shared_ptr planner); + + bool isInput() override; + void execute() override; + }; +} + +#endif //EDITCONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/EqualityConstraint.cpp b/benchmarks/C++/src/deltablue/EqualityConstraint.cpp new file mode 100644 index 00000000..b5ff7db4 --- /dev/null +++ b/benchmarks/C++/src/deltablue/EqualityConstraint.cpp @@ -0,0 +1,16 @@ +#include "EqualityConstraint.h" + +namespace deltablue { + EqualityConstraint::EqualityConstraint(shared_ptr var1, shared_ptr var2, shared_ptr strength, shared_ptr planner) + : BinaryConstraint(var1, var2, strength/*, planner*/) { + //addConstraint(planner); + } + + void EqualityConstraint::execute() { + if (_direction == Direction::FORWARD) { + _v2->setValue(_v1->getValue()); + } else { + _v1->setValue(_v2->getValue()); + } + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/EqualityConstraint.h b/benchmarks/C++/src/deltablue/EqualityConstraint.h new file mode 100644 index 00000000..db106587 --- /dev/null +++ b/benchmarks/C++/src/deltablue/EqualityConstraint.h @@ -0,0 +1,20 @@ +#ifndef EQUALITYCONSTRAINT +#define EQUALITYCONSTRAINT + +#include "BinaryConstraint.h" +#include "Strength.h" +#include "Direction.h" +#include + +using namespace std; + +namespace deltablue { + class EqualityConstraint : public BinaryConstraint { + public: + EqualityConstraint(shared_ptr var1, shared_ptr var2, shared_ptr strength, shared_ptr planner); + + void execute() override; + }; +} + +#endif //EQUALITYCONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Plan.cpp b/benchmarks/C++/src/deltablue/Plan.cpp new file mode 100644 index 00000000..2198940e --- /dev/null +++ b/benchmarks/C++/src/deltablue/Plan.cpp @@ -0,0 +1,14 @@ +#include "Plan.h" + +using namespace std; + +namespace deltablue { + + Plan::Plan() : Vector>() {} + + void Plan::execute() { + forEach([&](shared_ptr c) -> void { + c->execute(); + }); + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Plan.h b/benchmarks/C++/src/deltablue/Plan.h new file mode 100644 index 00000000..4b836723 --- /dev/null +++ b/benchmarks/C++/src/deltablue/Plan.h @@ -0,0 +1,19 @@ +#ifndef PLAN +#define PLAN + +#include "AbstractConstraint.h" +#include "../som/Vector.cpp" + +using namespace std; + +namespace deltablue { + + class Plan : public Vector> { + public: + Plan(); + + void execute(); + }; +} + +#endif //PLAN \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Planner.cpp b/benchmarks/C++/src/deltablue/Planner.cpp new file mode 100644 index 00000000..480c6017 --- /dev/null +++ b/benchmarks/C++/src/deltablue/Planner.cpp @@ -0,0 +1,230 @@ +#include "Planner.h" +#include + +using namespace std; + +namespace deltablue { + + Planner::Planner() { + _currentMark = 1; + } + + void Planner::incrementalAdd(shared_ptr c) { + int mark = newMark(); + shared_ptr overridden = c->satisfy(mark, shared_ptr()); + + while (overridden != nullptr) { + overridden = overridden->satisfy(mark, shared_ptr()); + } + } + + void Planner::incrementalRemove(shared_ptr c) { + shared_ptr out = c->getOutput(); + c->markUnsatisfied(); + c->removeFromGraph(); + + shared_ptr>> unsatisfied = removePropagateFrom(out); + unsatisfied->forEach([&](shared_ptr u) -> void { + incrementalAdd(u); + }); + } + + shared_ptr Planner::extractPlanFromConstraints(shared_ptr>> constraints) { + shared_ptr>> sources = make_shared>>(); + constraints->forEach([&](shared_ptr c) -> void { + if (c->isInput() && c->isSatisfied()) { + sources->append(c); + } + }); + return makePlan(sources); + } + + shared_ptr Planner::makePlan(shared_ptr>> sources) { + int mark = newMark(); + shared_ptr plan = make_shared(); + shared_ptr>> todo = sources; + + while (!todo->isEmpty()) { + shared_ptr c = todo->removeFirst(); + + if (c->getOutput()->getMark() != mark && c->inputsKnown(mark)) { + plan->append(c); + c->getOutput()->setMark(mark); + addConstraintsConsumingTo(c->getOutput(), todo); + } + } + + return plan; + } + + void Planner::propagateFrom(shared_ptr v) { + shared_ptr>> todo = make_shared>>(); + addConstraintsConsumingTo(v, todo); + + while (!todo->isEmpty()) { + shared_ptr c = todo->removeFirst(); + c->execute(); + addConstraintsConsumingTo(c->getOutput(), todo); + } + } + + void Planner::addConstraintsConsumingTo(shared_ptr v, shared_ptr>> coll) { + shared_ptr determiningC = v->getDeterminedBy(); + + v->getConstraints()->forEach([&](shared_ptr c) -> void { + if (c != determiningC && c->isSatisfied()) { + coll->append(c); + } + }); + } + + bool Planner::addPropagate(shared_ptr c, int mark) { + shared_ptr>> todo = Vector>::with(c); + + while (!todo->isEmpty()) { + shared_ptr d = todo->removeFirst(); + + if (d->getOutput()->getMark() == mark) { + incrementalRemove(c); + return false; + } + + d->recalculate(); + addConstraintsConsumingTo(d->getOutput(), todo); + } + + return true; + } + + void Planner::change(shared_ptr var, int newValue) { + shared_ptr editC = make_shared(var, Strength::PREFERRED, shared_from_this()); + editC->addConstraint(shared_from_this()); + + shared_ptr>> editV = Vector>::with(editC); + shared_ptr plan = extractPlanFromConstraints(editV); + for (int i = 0; i < 10; i++) { + var->setValue(newValue); + plan->execute(); + } + + editC->destroyConstraint(shared_from_this()); + } + + void Planner::constraintsConsuming(shared_ptr v, function)> fn) { + shared_ptr determiningC = v->getDeterminedBy(); + + v->getConstraints()->forEach([&](shared_ptr c) -> void { + if (c != determiningC && c->isSatisfied()) { + fn(c); + } + }); + } + + int Planner::newMark() { + _currentMark++; + return _currentMark; + } + + shared_ptr>> Planner::removePropagateFrom(shared_ptr out) { + shared_ptr>> unsatisfied = make_shared>>(); + + out->setDeterminedBy(nullptr); + out->setWalkStrength(Strength::absoluteWeakest()); + out->setStay(true); + + shared_ptr>> todo = Vector>::with(out); + + while (!todo->isEmpty()) { + shared_ptr v = todo->removeFirst(); + + v->getConstraints()->forEach([&](shared_ptr c) -> void { + if (!c->isSatisfied()) { + unsatisfied->append(c); + } + }); + + constraintsConsuming(v, [&todo](shared_ptr c) -> void { + c->recalculate(); + todo->append(c->getOutput()); + }); + } + + unsatisfied->sort([&](shared_ptr c1, shared_ptr c2) -> int { + return c1->getStrength()->stronger(c2->getStrength()) ? -1 : 1; + + }); + + return unsatisfied; + } + + void Planner::chainTest(int n) { + Strength::initializeConstants(); + shared_ptr planner = make_shared(); + shared_ptr* vars = new shared_ptr[n + 1]; + for (int i = 0; i < n + 1; i++) { + vars[i] = make_shared(); + } + for (int i = 0; i < n; i++) { + shared_ptr v1 = vars[i]; + shared_ptr v2 = vars[i + 1]; + (make_shared(v1, v2, Strength::REQUIRED, planner))->addConstraint(planner); + } + (make_shared(vars[n], Strength::STRONG_DEFAULT, planner))->addConstraint(planner); + shared_ptr editC = make_shared(vars[0], Strength::PREFERRED, planner); + editC->addConstraint(planner); + shared_ptr>> editV = Vector>::with(editC); + shared_ptr plan = planner->extractPlanFromConstraints(editV); + + for (int i = 0; i < 100; i++) { + vars[0]->setValue(i); + plan->execute(); + if (vars[n]->getValue() != i) { + throw Error("Chain test failed!"); + } + } + editC->destroyConstraint(planner); + } + + void Planner::projectionTest(int n) { + shared_ptr planner = make_shared(); + shared_ptr>> dests = make_shared>>(); + + shared_ptr scale = Variable::value(10); + shared_ptr offset = Variable::value(1000); + + shared_ptr src = nullptr; + shared_ptr dst = nullptr; + for (int i = 1; i <= n; i++) { + src = Variable::value(i); + dst = Variable::value(i); + dests->append(dst); + (make_shared(src, Strength::DEFAULT, planner))->addConstraint(planner); + (make_shared(src, scale, offset, dst, Strength::REQUIRED, planner))->addConstraint(planner); + } + + planner->change(src, 17); + if (dst->getValue() != 1170) { + throw Error("Projection test 1 failed!"); + } + + planner->change(dst, 1050); + if (src->getValue() != 5) { + throw Error("Projection test 2 failed!"); + + } + + planner->change(scale, 5); + for (int i = 0; i < n - 1; ++i) { + if (dests->at(i)->getValue() != (i + 1) * 5 + 1000) { + throw Error("Projection test 3 failed!"); + } + } + + planner->change(offset, 2000); + for (int i = 0; i < n - 1; ++i) { + if (dests->at(i)->getValue() != (i + 1) * 5 + 2000) { + throw Error("Projection test 4 failed!"); + } + } + } +} diff --git a/benchmarks/C++/src/deltablue/Planner.h b/benchmarks/C++/src/deltablue/Planner.h new file mode 100644 index 00000000..22868b91 --- /dev/null +++ b/benchmarks/C++/src/deltablue/Planner.h @@ -0,0 +1,46 @@ +#ifndef PLANNER +#define PLANNER + +#include +#include +#include "AbstractConstraint.h" +#include "EqualityConstraint.h" +#include "ScaleConstraint.h" +#include "Plan.h" +#include "../som/Vector.cpp" +#include "StayConstraint.h" +#include "EditConstraint.h" + +using namespace std; + +namespace deltablue { + + class Planner : public enable_shared_from_this { + private: + int _currentMark; + + public: + Planner(); + + void incrementalAdd(shared_ptr c); + void incrementalRemove(shared_ptr c); + shared_ptr extractPlanFromConstraints(shared_ptr>> constraints); + shared_ptr makePlan(shared_ptr>> sources); + void propagateFrom(shared_ptr v); + void addConstraintsConsumingTo(shared_ptr v, shared_ptr>> coll); + bool addPropagate(shared_ptr c, int mark); + + void change(shared_ptr var, int newValue); + + void constraintsConsuming(shared_ptr v, function)> fn); + + int newMark(); + + shared_ptr>> removePropagateFrom(shared_ptr out); + + static void chainTest(int n); + static void projectionTest(int n); + }; +} + +#endif //PLANNER \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/ScaleConstraint.cpp b/benchmarks/C++/src/deltablue/ScaleConstraint.cpp new file mode 100644 index 00000000..f054eb2f --- /dev/null +++ b/benchmarks/C++/src/deltablue/ScaleConstraint.cpp @@ -0,0 +1,76 @@ +#include "ScaleConstraint.h" + +namespace deltablue { + + ScaleConstraint::ScaleConstraint(shared_ptr src, shared_ptr scale, shared_ptr offset, + shared_ptr dest, shared_ptr strength, shared_ptr planner) + : BinaryConstraint(src, dest, strength/*, planner*/) { + _strength = Strength::of(strength); + _v1 = src; + _v2 = dest; + _direction = NONE; + _scale = scale; + _offset = offset; + + //addConstraint(planner); + } + + void ScaleConstraint::addToGraph() { + _v1->addConstraint(shared_from_this()); + _v2->addConstraint(shared_from_this()); + _scale->addConstraint(shared_from_this()); + _offset->addConstraint(shared_from_this()); + _direction = NONE; + } + + void ScaleConstraint::removeFromGraph() { + if (_v1 != nullptr) + _v1->removeConstraint(shared_from_this()); + if (_v2 != nullptr) + _v2->removeConstraint(shared_from_this()); + if (_scale != nullptr) + _scale->removeConstraint(shared_from_this()); + if (_offset != nullptr) + _offset->removeConstraint(shared_from_this()); + _direction = NONE; + } + + void ScaleConstraint::execute() { + if (_direction == FORWARD) { + _v2->setValue(_v1->getValue() * _scale->getValue() + _offset->getValue()); + } else { + _v1->setValue((_v2->getValue() - _offset->getValue()) / _scale->getValue()); + } + } + + void ScaleConstraint::inputsDo(function)> fn) { + if (_direction == FORWARD) { + fn(_v1); + fn(_scale); + fn(_offset); + } else { + fn(_v2); + fn(_scale); + fn(_offset); + } + } + + void ScaleConstraint::recalculate() { + shared_ptr in; + shared_ptr out; + + if (_direction == FORWARD) { + in = _v1; + out = _v2; + } else { + out = _v1; + in = _v2; + } + + out->setWalkStrength(_strength->weakest(in->getWalkStrength())); + out->setStay(in->getStay() && _scale->getStay() && _offset->getStay()); + if (out->getStay()) { + execute(); // stay optimization + } + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/ScaleConstraint.h b/benchmarks/C++/src/deltablue/ScaleConstraint.h new file mode 100644 index 00000000..d9827c13 --- /dev/null +++ b/benchmarks/C++/src/deltablue/ScaleConstraint.h @@ -0,0 +1,31 @@ +#ifndef SCALECONSTRAINT +#define SCALECONSTRAINT + + +#include "BinaryConstraint.h" +#include "Variable.h" +#include + +using namespace std; + +namespace deltablue { + class ScaleConstraint :public BinaryConstraint { + private: + shared_ptr _scale; + shared_ptr _offset; + + public: + ScaleConstraint(shared_ptr src, shared_ptr scale, shared_ptr offset, + shared_ptr dest, shared_ptr strength, shared_ptr planner); + + void addToGraph() override; + + void removeFromGraph() override; + void execute() override; + + void inputsDo(function)> fn) override; + void recalculate() override; + }; +} + +#endif //SCALECONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/StayConstraint.cpp b/benchmarks/C++/src/deltablue/StayConstraint.cpp new file mode 100644 index 00000000..e2e719a6 --- /dev/null +++ b/benchmarks/C++/src/deltablue/StayConstraint.cpp @@ -0,0 +1,11 @@ +#include "StayConstraint.h" + +using namespace std; + +namespace deltablue { + + StayConstraint::StayConstraint(shared_ptr v, shared_ptr strength, + shared_ptr planner) : UnaryConstraint(v, strength, planner) {} + + void StayConstraint::execute() {} +} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/StayConstraint.h b/benchmarks/C++/src/deltablue/StayConstraint.h new file mode 100644 index 00000000..a72f4526 --- /dev/null +++ b/benchmarks/C++/src/deltablue/StayConstraint.h @@ -0,0 +1,22 @@ +#ifndef STAYCONSTRAINT +#define STAYCONSTRAINT + +#include "UnaryConstraint.h" +#include "Planner.h" + +using namespace std; + +namespace deltablue { + + class StayConstraint : public UnaryConstraint { + public: + + StayConstraint(shared_ptr v, shared_ptr strength, + shared_ptr planner); + + void execute() override; + + }; +} + +#endif //STAYCONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Strength.cpp b/benchmarks/C++/src/deltablue/Strength.cpp new file mode 100644 index 00000000..fc0d9eec --- /dev/null +++ b/benchmarks/C++/src/deltablue/Strength.cpp @@ -0,0 +1,103 @@ +#include "Strength.h" + +using namespace std; + +namespace deltablue { + + shared_ptr> Strength::_strengthTable; + shared_ptr>> Strength::_strengthConstant; + shared_ptr Strength::_absoluteWeakest; + shared_ptr Strength::_required; + + // Set static member variable + shared_ptr Strength::ABSOLUTE_STRONGEST = make_shared(0); + shared_ptr Strength::REQUIRED = make_shared(1); + shared_ptr Strength::STRONG_PREFERRED = make_shared(2); + shared_ptr Strength::PREFERRED = make_shared(3); + shared_ptr Strength::STRONG_DEFAULT = make_shared(4); + shared_ptr Strength::DEFAULT = make_shared(5); + shared_ptr Strength::WEAK_DEFAULT = make_shared(6); + shared_ptr Strength::ABSOLUTE_WEAKEST = make_shared(7); + + Strength::Sym::Sym(int hash) { + _hash = hash; + } + + int Strength::Sym::customHash() { + return _hash; + } + + Strength::Strength(shared_ptr symbolicValue) { + _symbolicValue = symbolicValue; + _arithmeticValue = _strengthTable->at(symbolicValue); + } + + + bool Strength::sameAs(shared_ptr s) const { + return _arithmeticValue == s->_arithmeticValue; + } + + bool Strength::stronger(shared_ptr s) const { + return _arithmeticValue < s->_arithmeticValue; + } + + bool Strength::weaker(shared_ptr s) const { + return _arithmeticValue > s->_arithmeticValue; + } + + shared_ptr Strength::strongest(shared_ptr s) { + return s->stronger(shared_from_this()) ? s : shared_from_this(); + } + + shared_ptr Strength::weakest(shared_ptr s) { + return s->weaker(shared_from_this()) ? s : shared_from_this(); + } + + int Strength::get_arithmeticValue() const { + return _arithmeticValue; + } + + shared_ptr Strength::of(shared_ptr strength) { + return _strengthConstant->atPtr(strength); + } + + shared_ptr Strength::absoluteWeakest() { + return _absoluteWeakest; + } + + shared_ptr Strength::required() { + return _required; + } + + shared_ptr> Strength::createStrengthTable() { + shared_ptr> strengthTable = make_shared>(); + strengthTable->atPut(Strength::ABSOLUTE_STRONGEST, -10000); + strengthTable->atPut(Strength::REQUIRED, -800); + strengthTable->atPut(Strength::STRONG_PREFERRED, -600); + strengthTable->atPut(Strength::PREFERRED, -400); + strengthTable->atPut(Strength::STRONG_DEFAULT, -200); + strengthTable->atPut(Strength::DEFAULT, 0); + strengthTable->atPut(Strength::WEAK_DEFAULT, 500); + strengthTable->atPut(Strength::ABSOLUTE_WEAKEST, 10000); + return strengthTable; + } + + + shared_ptr>> Strength::createStrengthConstants() { + shared_ptr>> strengthConstant = make_shared>>(); + _strengthTable->getKeys()->forEach([&](shared_ptr key) -> void { + shared_ptr keySym = dynamic_pointer_cast(key); + strengthConstant->atPut(keySym, make_shared(keySym)); + }); + + return strengthConstant; + } + + void Strength::initializeConstants() { + _strengthTable = createStrengthTable(); + _strengthConstant = createStrengthConstants(); + _absoluteWeakest = of(Strength::ABSOLUTE_WEAKEST); + _required = of(Strength::REQUIRED); + } + +} diff --git a/benchmarks/C++/src/deltablue/Strength.h b/benchmarks/C++/src/deltablue/Strength.h new file mode 100644 index 00000000..6719e881 --- /dev/null +++ b/benchmarks/C++/src/deltablue/Strength.h @@ -0,0 +1,68 @@ +#ifndef STRENGTH +#define STRENGTH + +#include +#include +#include "../som/Dictionary.cpp" +#include "../som/IdentityDictionary.cpp" + +using namespace std; + +namespace deltablue { + class Strength : public enable_shared_from_this { + public: + class Sym : public CustomHash { + private: + int _hash; + + public: + Sym(int hash); + + int customHash() override; + }; + + static shared_ptr ABSOLUTE_STRONGEST; + static shared_ptr REQUIRED; + static shared_ptr STRONG_PREFERRED; + static shared_ptr PREFERRED; + static shared_ptr STRONG_DEFAULT; + static shared_ptr DEFAULT; + static shared_ptr WEAK_DEFAULT; + static shared_ptr ABSOLUTE_WEAKEST; + + private: + + int _arithmeticValue; + shared_ptr _symbolicValue; + + static shared_ptr> createStrengthTable(); + static shared_ptr>> createStrengthConstants(); + + public: + Strength(shared_ptr symbolicValue); + + bool sameAs(shared_ptr s) const; + bool stronger(shared_ptr s) const; + bool weaker(shared_ptr s) const; + shared_ptr strongest(shared_ptr s); + shared_ptr weakest(shared_ptr s); + int get_arithmeticValue() const; + static shared_ptr of(shared_ptr strength); + static shared_ptr absoluteWeakest(); + static shared_ptr required(); + static void initializeConstants(); + private: + + static shared_ptr _absoluteWeakest; + static shared_ptr _required; + + static shared_ptr> _strengthTable; + static shared_ptr>> _strengthConstant; + + }; + + + +} + +#endif //STRENGTHPLAN \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/UnaryConstraint.cpp b/benchmarks/C++/src/deltablue/UnaryConstraint.cpp new file mode 100644 index 00000000..0e42f2b8 --- /dev/null +++ b/benchmarks/C++/src/deltablue/UnaryConstraint.cpp @@ -0,0 +1,60 @@ +#include +#include "UnaryConstraint.h" + +using namespace std; + +namespace deltablue { + UnaryConstraint::UnaryConstraint(shared_ptr v, shared_ptr strength, shared_ptr planner) + : AbstractConstraint(strength) { + _output = v; + _satisfied = false; + //addConstraint(planner); + } + + bool UnaryConstraint::isSatisfied() { + return _satisfied; + } + + // Add myself to the constraint graph. + void UnaryConstraint::addToGraph() { + _output->addConstraint(shared_from_this()); + _satisfied = false; + } + + // Remove myself from the constraint graph. + void UnaryConstraint::removeFromGraph() { + if (_output != nullptr) { + _output->removeConstraint(shared_from_this()); + } + _satisfied = false; + } + + Direction UnaryConstraint::chooseMethod(int mark) { + _satisfied = (_output->getMark() != mark) && _strength->stronger(_output->getWalkStrength()); + return NONE; + } + + void UnaryConstraint::inputsDo(function)> fn) { + // I have no input variables + } + + bool UnaryConstraint::inputsHasOne(function)> fn) { + return false; + } + + void UnaryConstraint::markUnsatisfied() { + _satisfied = false; + } + + shared_ptr UnaryConstraint::getOutput() { + return _output; + } + + void UnaryConstraint::recalculate() { + _output->setWalkStrength(_strength); + _output->setStay(!isInput()); + if (_output->getStay()) { + execute(); + } + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/UnaryConstraint.h b/benchmarks/C++/src/deltablue/UnaryConstraint.h new file mode 100644 index 00000000..2690de3d --- /dev/null +++ b/benchmarks/C++/src/deltablue/UnaryConstraint.h @@ -0,0 +1,32 @@ +#ifndef UNARYCONSTRAINT +#define UNARYCONSTRAINT + +#include +#include "AbstractConstraint.h" + +using namespace std; + +namespace deltablue { + class UnaryConstraint : public AbstractConstraint { + protected: + shared_ptr _output; // possible output variable + bool _satisfied; // true if I am currently satisfied + + public: + UnaryConstraint(shared_ptr v, shared_ptr strength, shared_ptr planner); + + bool isSatisfied() override; + void addToGraph() override; + void removeFromGraph() override; + Direction chooseMethod(int mark) override; + virtual void execute() = 0; + void inputsDo(function)> fn) override; + bool inputsHasOne(function)> fn) override; + void markUnsatisfied() override; + shared_ptr getOutput() override; + void recalculate() override; + + }; +} + +#endif //UNARYCONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Variable.cpp b/benchmarks/C++/src/deltablue/Variable.cpp new file mode 100644 index 00000000..456b2def --- /dev/null +++ b/benchmarks/C++/src/deltablue/Variable.cpp @@ -0,0 +1,77 @@ +#include "AbstractConstraint.h" + +using namespace std; + +namespace deltablue { + + shared_ptr Variable::value(int aValue) { + shared_ptr v = make_shared(); + v->setValue(aValue); + return v; + } + + Variable::Variable() { + _value = 0; + _constraints = make_shared>>(2); + _determinedBy = nullptr; + _walkStrength = Strength::absoluteWeakest(); + _stay = true; + _mark = 0; + } + + void Variable::addConstraint(shared_ptr c) { + _constraints->append(c); + } + + shared_ptr>> Variable::getConstraints() { + return _constraints; + } + + shared_ptr Variable::getDeterminedBy() const { + return _determinedBy; + } + + void Variable::setDeterminedBy(shared_ptr c) { + _determinedBy = c; + } + + int Variable::getMark() const { + return _mark; + } + + void Variable::setMark(int markValue) { + _mark = markValue; + } + + void Variable::removeConstraint(shared_ptr c) { + _constraints->remove(c); + if (_determinedBy == c) { + _determinedBy = nullptr; + } + } + + bool Variable::getStay() const { + return _stay; + } + + void Variable::setStay(bool v) { + _stay = v; + } + + int Variable::getValue() const { + return _value; + } + + void Variable::setValue(int value) { + _value = value; + } + + shared_ptr Variable::getWalkStrength() { + return _walkStrength; + } + + void Variable::setWalkStrength(shared_ptr strength) { + _walkStrength = strength; + } + +} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Variable.h b/benchmarks/C++/src/deltablue/Variable.h new file mode 100644 index 00000000..ca247b8c --- /dev/null +++ b/benchmarks/C++/src/deltablue/Variable.h @@ -0,0 +1,44 @@ +#ifndef VARIABLE +#define VARIABLE + +#include "Strength.h" +#include "../som/Vector.cpp" +#include + +using namespace std; + +namespace deltablue { + + class AbstractConstraint; + + class Variable { + private: + + int _value; + shared_ptr>> _constraints; + shared_ptr _determinedBy; + int _mark; + shared_ptr _walkStrength; + bool _stay; + + public: + Variable(); + + static shared_ptr value(int aValue); + void addConstraint(shared_ptr c); + shared_ptr>> getConstraints(); + shared_ptr getDeterminedBy() const; + void setDeterminedBy(shared_ptr c); + int getMark() const; + void setMark(int markValue); + void removeConstraint(shared_ptr c); + bool getStay() const; + void setStay(bool v); + int getValue() const; + void setValue(int value); + shared_ptr getWalkStrength(); + void setWalkStrength(shared_ptr strength); + }; +} + +#endif //VARIABLE \ No newline at end of file diff --git a/benchmarks/C++/src/som/Dictionary.cpp b/benchmarks/C++/src/som/Dictionary.cpp new file mode 100644 index 00000000..b05814b1 --- /dev/null +++ b/benchmarks/C++/src/som/Dictionary.cpp @@ -0,0 +1,259 @@ +#ifndef DICTIONARY +#define DICTIONARY + + +#include +#include "Vector.cpp" + +class CustomHash { + public: + CustomHash() = default; + virtual int customHash()=0; +}; + +template +class Dictionary { + + public: + class Entry { + public: + int _hash; + shared_ptr _key; + V _value; + std::shared_ptr _next; + + public: + Entry(int h, const shared_ptr& k, const V& v, std::shared_ptr n) + : _hash(h), _key(k), _value(v), _next(n) {} + + virtual bool match(int h, const shared_ptr& k) { + return _hash == h && _key == k; + } + + const shared_ptr& getKey() const { + return _key; + } + + int getHash() const { + return _hash; + } + }; + + static const int INITIAL_CAPACITY = 16; + + std::shared_ptr* _buckets; + int _size; + int _capacity; + + public: + Dictionary(int capacity = INITIAL_CAPACITY) : _size(0), _capacity(capacity) { + _buckets = new std::shared_ptr[capacity](); + } + + ~Dictionary() { + removeAll(); + delete[] _buckets; + } + + int getSize() const { + return _size; + } + + bool isEmpty() const { + return _size == 0; + } + + int hash(const shared_ptr& key) const { + if (key == nullptr) { + return 0; + } + int h = key->customHash(); + return h ^ (h >> 16); + } + + bool containsKey(const shared_ptr& key) const { + int h = hash(key); + std::shared_ptr e = getBucket(h); + + while (e != nullptr) { + if (e->match(h, key)) { + return true; + } + e = e->_next; + } + return false; + } + + V atPtr(const shared_ptr& key) const { + int h = hash(key); + std::shared_ptr e = getBucket(h); + + while (e != nullptr) { + if (e->match(h, key)) { + return e->_value; + } + e = e->_next; + } + return nullptr; + } + + + V at(const shared_ptr& key) const { + int h = this->hash(key); + std::shared_ptr e = getBucket(h); + + while (e != nullptr) { + if (e->match(h, key)) { + return e->_value; + } + e = e->_next; + } + // Return a default-constructed V if the key is not found + return V(); + } + + void atPut(const shared_ptr& key, const V& value) { + int h = hash(key); + int i = getBucketIdx(h); + + std::shared_ptr current = _buckets[i]; + + if (current == nullptr) { + _buckets[i] = newEntry(key, value, h); + _size += 1; + } else { + insertBucketEntry(key, value, h, current); + } + + if (_size > _capacity) { + resize(); + } + } + + void removeAll() { + for(int i = 0; i < _capacity; i++) { + _buckets[i] = nullptr; // Reset each element to a default value + } + _size = 0; + } + + shared_ptr>> getKeys() { + shared_ptr>> keys = make_shared>>(); + for (int i = 0; i < _capacity; i++) { + std::shared_ptr current = _buckets[i]; + while (current != nullptr) { + keys->append(current->_key); + current = current->_next; + } + } + return keys; + } + + shared_ptr> getValues() { + shared_ptr> values = make_shared>(_size); + + for (int i = 0; i < _capacity; i++) { + std::shared_ptr current = _buckets[i]; + while (current != nullptr) { + values->append(current->_value); + current = current->_next; + } + } + return values; + } + + virtual std::shared_ptr newEntry(shared_ptr key, V value, int hash) { + return make_shared(hash, key, value, nullptr); + } + + private: + int getBucketIdx(int hash) const { + return (_capacity - 1) & hash; + } + + std::shared_ptr getBucket(int hash) const { + return _buckets[getBucketIdx(hash)]; + } + + void insertBucketEntry(const shared_ptr& key, const V& value, int hash, std::shared_ptr head) { + std::shared_ptr current = head; + + while (true) { + if (current->match(hash, key)) { + current->_value = value; + return; + } + if (current->_next == nullptr) { + _size += 1; + current->_next = newEntry(key, value, hash); + return; + } + current = current->_next; + } + } + + void resize() { + std::shared_ptr* oldStorage = _buckets; + int oldCapacity = _capacity; + _capacity *= 2; + std::shared_ptr* newStorage = new shared_ptr[_capacity](); + _buckets = newStorage; + transferEntries(oldStorage, oldCapacity); + delete[] oldStorage; + } + + void transferEntries(std::shared_ptr* oldStorage, int oldCapacity) { + for (int i = 0; i < oldCapacity; i++) { + shared_ptr current = oldStorage[i]; + if (current != nullptr) { + oldStorage[i] = nullptr; + if (current->_next == nullptr) { + _buckets[current->_hash & (oldCapacity - 1)] = current; + } else { + splitBucket(i, current, oldCapacity); + } + } + } + } + + void splitBucket(int idx, std::shared_ptr head, int oldCapacity) { + std::shared_ptr loHead = nullptr; + std::shared_ptr loTail = nullptr; + std::shared_ptr hiHead = nullptr; + std::shared_ptr hiTail = nullptr; + + std::shared_ptr current = head; + + while (current != nullptr) { + if ((current->_hash & oldCapacity) == 0) { + if (loTail == nullptr) { + loHead = current; + } else { + loTail->_next = current; + } + loTail = current; + } else { + if (hiTail == nullptr) { + hiHead = current; + } else { + hiTail->_next = current; + } + hiTail = current; + } + current = current->_next; + } + + if (loTail != nullptr) { + loTail->_next = nullptr; + _buckets[idx] = loHead; + } + if (hiTail != nullptr) { + hiTail->_next = nullptr; + _buckets[idx + oldCapacity] = hiHead; + } + } + +}; + + +#endif //DICTIONARY \ No newline at end of file diff --git a/benchmarks/C++/src/som/Error.cpp b/benchmarks/C++/src/som/Error.cpp new file mode 100644 index 00000000..c5d6621a --- /dev/null +++ b/benchmarks/C++/src/som/Error.cpp @@ -0,0 +1,27 @@ + +#ifndef ERROR +#define ERROR + +#include + +using namespace std; + +class Error : virtual public exception { + private: + string _what; + + public: + Error(string const &what) { + _what = what; + } + + Error(const char *what) { + _what = string(what); + } + + const char *what() const throw() { + return (_what.c_str()); + } +}; + +#endif //ERROR \ No newline at end of file diff --git a/benchmarks/C++/src/som/IdentityDictionary.cpp b/benchmarks/C++/src/som/IdentityDictionary.cpp new file mode 100644 index 00000000..cf433227 --- /dev/null +++ b/benchmarks/C++/src/som/IdentityDictionary.cpp @@ -0,0 +1,29 @@ +#ifndef IDENTITYDICTIONARY +#define IDENTITYDICTIONARY + +#include "Dictionary.cpp" +#include + +template +class IdentityDictionary : public Dictionary { + public: + class IdEntry : public Dictionary::Entry { + public: + IdEntry(int hash, const shared_ptr& key, const V& value, std::shared_ptr::Entry> next) + : Dictionary::Entry(hash, key, value, next) {} + + bool match(int h, const shared_ptr& k) override { + return this->getHash() == h && this->getKey() == k; + } + }; + + public: + IdentityDictionary(const int size) : Dictionary(size) {} + IdentityDictionary() : Dictionary(Dictionary::INITIAL_CAPACITY) {} + + std::shared_ptr::Entry> newEntry(shared_ptr key, V value, int hash) override { + return make_shared(hash, key, value, nullptr); + } +}; + +#endif //IDENTITYDICTIONARY \ No newline at end of file diff --git a/benchmarks/C++/src/som/Vector.cpp b/benchmarks/C++/src/som/Vector.cpp new file mode 100644 index 00000000..920bd7a7 --- /dev/null +++ b/benchmarks/C++/src/som/Vector.cpp @@ -0,0 +1,240 @@ +#ifndef VECTOR +#define VECTOR + +#include +#include +#include +#include +#include +#include +using namespace std; + +template +class Vector { + private: + E* storage; + size_t _capacity; + size_t _firstIdx; + size_t _lastIdx; + + static void swap(E* storage2, int i, int j) { + throw std::logic_error("Function swap not yet implemented"); + } + + void defaultSort(int i, int j) { + throw std::logic_error("Function defaultSort not yet implemented"); + } + + void sort(int i, int j, std::function c) { + if (c == nullptr) { + defaultSort(i, j); + return; // Make sure to return if c is nullptr. + } + + int n = j + 1 - i; + if (n <= 1) { + return; + } + + E di = storage[i]; + E dj = storage[j]; + + if (c(di, dj) > 0) { + swap(storage, i, j); + E tt = di; + di = dj; + dj = tt; + } + + if (n > 2) { + int ij = (i + j) / 2; + E dij = storage[ij]; + + if (c(di, dij) <= 0) { + if (c(dij, dj) > 0) { + swap(storage, j, ij); + dij = dj; + } + } else { + swap(storage, i, ij); + dij = di; + } + + if (n > 3) { + int k = i; + int l = j - 1; + + while (true) { + while (k <= l && c(dij, storage[l]) <= 0) { + l -= 1; + } + + k += 1; + while (k <= l && c(storage[k], dij) <= 0) { + k += 1; + } + + if (k > l) { + break; + } + swap(storage, k, l); + } + + sort(i, l, c); + sort(k, j, c); + } + } + } + + + + public: + static shared_ptr> with(const E& elem) { + shared_ptr> v = make_shared>(1); + v->append(elem); + return v; + } + + explicit Vector(size_t size) : _capacity(size), _firstIdx(0), _lastIdx(0) { + storage = new E[_capacity]; + } + + Vector() : Vector(50) {} + + ~Vector() { + delete[] storage; + } + + E atPtr(size_t idx) const { + if (idx >= _lastIdx - _firstIdx) { + return nullptr; + } + return storage[_firstIdx + idx]; + } + + E at(size_t idx) const { + if (idx >= _lastIdx - _firstIdx) { + return E(); + } + return storage[_firstIdx + idx]; + } + + void atPut(size_t idx, const E& val) { + if (idx >= _lastIdx - _firstIdx) { + size_t newLength = _capacity; + while (newLength <= idx + _firstIdx) { + newLength *= 2; + } + E* newStorage = new E[newLength]; + for (size_t i = 0; i < _lastIdx; i++) { + newStorage[i] = storage[i]; + } + delete[] storage; + storage = newStorage; + _capacity = newLength; + } + storage[_firstIdx + idx] = val; + if (_lastIdx < idx + 1) { + _lastIdx = idx + 1; + } + } + + void append(const E& elem) { + if (_lastIdx >= _capacity) { + // Need to expand _capacity first + _capacity *= 2; + E* newStorage = new E[_capacity]; + for (size_t i = 0; i < _lastIdx; i++) { + newStorage[i] = storage[i]; + } + delete[] storage; + storage = newStorage; + } + + storage[_lastIdx] = elem; + _lastIdx++; + } + + + bool isEmpty() const { + return _lastIdx == _firstIdx; + } + + void forEach(const std::function& fn) const { + for (size_t i = _firstIdx; i < _lastIdx; i++) { + fn(storage[i]); + } + } + + bool hasSome(const std::function& fn) const { + for (size_t i = _firstIdx; i < _lastIdx; i++) { + if (fn(storage[i])) { + return true; + } + } + return false; + } + + E getOne(const std::function& fn) const { + for (size_t i = _firstIdx; i < _lastIdx; i++) { + const E& e = storage[i]; + if (fn(e)) { + return e; + } + } + return nullptr; // Return a default-constructed object if not found + } + + E first() const { + if (isEmpty()) { + return nullptr; // Return a default-constructed object for an empty vector + } + return storage[_firstIdx]; + } + + E removeFirst() { + if (isEmpty()) { + return nullptr; // Return a default-constructed object for an empty vector + } + _firstIdx++; + return storage[_firstIdx - 1]; + } + + bool remove(const E& obj) { + bool found = false; + size_t newLast = _firstIdx; + for (size_t i = _firstIdx; i < _lastIdx; i++) { + if (storage[i] == obj) { + found = true; + } else { + storage[newLast] = storage[i]; + newLast++; + } + } + _lastIdx = newLast; + return found; + } + + void removeAll() { + _firstIdx = 0; + _lastIdx = 0; + } + + size_t size() const { + return _lastIdx - _firstIdx; + } + + size_t getCapacity() const { + return _capacity; + } + + void sort(std::function c) { + if (size() > 0) { + sort(_firstIdx, _lastIdx - 1, c); + } + } + + +}; + +#endif //VECTOR From c1cf5bbeca46002de2a8e548be9e8c8ec5f1a4c2 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 3 Jan 2024 14:40:54 +0000 Subject: [PATCH 03/40] [C++] Match style by putting all code into headers where possible and into the deltablue.h and deltablue.cpp files only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - call addConstraint in the leaf class We can’t call addConstraint further up in the hierarchy, because then the wrong virtual methods get called. This is likely a C++ ordering issues with constructors and vtables… - manually manage memory and fix memory leaks - added destructor for Variable - use auto to make code more concise - added sanitize option to build.sh - use size_t consistently for indexes in vector.h - use {} after new Type*[size] is said to make sure the array is nullptr initialized - need to free the entry objects when doing Dictionary::removeAll - do not manually free the constraint in DeltaBlue, since it’s done implicitly by object tracking - allow do-while in .clang-tidy Signed-off-by: Stefan Marr --- benchmarks/C++/.clang-tidy | 39 +- benchmarks/C++/build.sh | 15 +- benchmarks/C++/src/benchmark.h | 4 +- benchmarks/C++/src/deltablue.cpp | 102 +++ benchmarks/C++/src/deltablue.h | 712 ++++++++++++++++++ .../C++/src/deltablue/AbstractConstraint.cpp | 67 -- .../C++/src/deltablue/AbstractConstraint.h | 48 -- .../C++/src/deltablue/BinaryConstraint.cpp | 110 --- .../C++/src/deltablue/BinaryConstraint.h | 28 - benchmarks/C++/src/deltablue/Direction.h | 10 - .../C++/src/deltablue/EditConstraint.cpp | 15 - benchmarks/C++/src/deltablue/EditConstraint.h | 22 - .../C++/src/deltablue/EqualityConstraint.cpp | 16 - .../C++/src/deltablue/EqualityConstraint.h | 20 - benchmarks/C++/src/deltablue/Plan.cpp | 14 - benchmarks/C++/src/deltablue/Plan.h | 19 - benchmarks/C++/src/deltablue/Planner.cpp | 230 ------ benchmarks/C++/src/deltablue/Planner.h | 46 -- .../C++/src/deltablue/ScaleConstraint.cpp | 76 -- .../C++/src/deltablue/ScaleConstraint.h | 31 - .../C++/src/deltablue/StayConstraint.cpp | 11 - benchmarks/C++/src/deltablue/StayConstraint.h | 22 - benchmarks/C++/src/deltablue/Strength.cpp | 103 --- benchmarks/C++/src/deltablue/Strength.h | 68 -- .../C++/src/deltablue/UnaryConstraint.cpp | 60 -- .../C++/src/deltablue/UnaryConstraint.h | 32 - benchmarks/C++/src/deltablue/Variable.cpp | 77 -- benchmarks/C++/src/deltablue/Variable.h | 44 -- benchmarks/C++/src/run.h | 6 +- benchmarks/C++/src/som/Dictionary.cpp | 259 ------- benchmarks/C++/src/som/Error.cpp | 27 - benchmarks/C++/src/som/IdentityDictionary.cpp | 29 - benchmarks/C++/src/som/Vector.cpp | 240 ------ benchmarks/C++/src/som/dictionary.h | 268 +++++++ benchmarks/C++/src/som/error.h | 18 + benchmarks/C++/src/som/identity_dictionary.h | 32 + benchmarks/C++/src/som/random.h | 9 +- benchmarks/C++/src/som/vector.h | 225 ++++++ benchmarks/C++/src/storage.h | 4 +- 39 files changed, 1421 insertions(+), 1737 deletions(-) create mode 100644 benchmarks/C++/src/deltablue.cpp create mode 100644 benchmarks/C++/src/deltablue.h delete mode 100644 benchmarks/C++/src/deltablue/AbstractConstraint.cpp delete mode 100644 benchmarks/C++/src/deltablue/AbstractConstraint.h delete mode 100644 benchmarks/C++/src/deltablue/BinaryConstraint.cpp delete mode 100644 benchmarks/C++/src/deltablue/BinaryConstraint.h delete mode 100644 benchmarks/C++/src/deltablue/Direction.h delete mode 100644 benchmarks/C++/src/deltablue/EditConstraint.cpp delete mode 100644 benchmarks/C++/src/deltablue/EditConstraint.h delete mode 100644 benchmarks/C++/src/deltablue/EqualityConstraint.cpp delete mode 100644 benchmarks/C++/src/deltablue/EqualityConstraint.h delete mode 100644 benchmarks/C++/src/deltablue/Plan.cpp delete mode 100644 benchmarks/C++/src/deltablue/Plan.h delete mode 100644 benchmarks/C++/src/deltablue/Planner.cpp delete mode 100644 benchmarks/C++/src/deltablue/Planner.h delete mode 100644 benchmarks/C++/src/deltablue/ScaleConstraint.cpp delete mode 100644 benchmarks/C++/src/deltablue/ScaleConstraint.h delete mode 100644 benchmarks/C++/src/deltablue/StayConstraint.cpp delete mode 100644 benchmarks/C++/src/deltablue/StayConstraint.h delete mode 100644 benchmarks/C++/src/deltablue/Strength.cpp delete mode 100644 benchmarks/C++/src/deltablue/Strength.h delete mode 100644 benchmarks/C++/src/deltablue/UnaryConstraint.cpp delete mode 100644 benchmarks/C++/src/deltablue/UnaryConstraint.h delete mode 100644 benchmarks/C++/src/deltablue/Variable.cpp delete mode 100644 benchmarks/C++/src/deltablue/Variable.h delete mode 100644 benchmarks/C++/src/som/Dictionary.cpp delete mode 100644 benchmarks/C++/src/som/Error.cpp delete mode 100644 benchmarks/C++/src/som/IdentityDictionary.cpp delete mode 100644 benchmarks/C++/src/som/Vector.cpp create mode 100644 benchmarks/C++/src/som/dictionary.h create mode 100644 benchmarks/C++/src/som/error.h create mode 100644 benchmarks/C++/src/som/identity_dictionary.h create mode 100644 benchmarks/C++/src/som/vector.h diff --git a/benchmarks/C++/.clang-tidy b/benchmarks/C++/.clang-tidy index e99465a6..abc54eb8 100644 --- a/benchmarks/C++/.clang-tidy +++ b/benchmarks/C++/.clang-tidy @@ -1,5 +1,42 @@ --- -Checks: '*,-modernize-use-trailing-return-type,-altera-unroll-loops,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-llvm-header-guard,-llvmlibc-*,-misc-no-recursion,-concurrency-mt-unsafe,-readability-identifier-length,-misc-use-anonymous-namespace,-readability-convert-member-functions-to-static,-bugprone-easily-swappable-parameters,-fuchsia-default-arguments-calls,-hicpp-named-parameter,-readability-named-parameter,-altera-id-dependent-backward-branch,-readability-delete-null-pointer,-cppcoreguidelines-avoid-const-or-ref-data-members,-cppcoreguidelines-pro-bounds-constant-array-index' +Checks: '*, + -modernize-use-trailing-return-type, + -altera-id-dependent-backward-branch, + -altera-unroll-loops, + -bugprone-easily-swappable-parameters, + -bugprone-exception-escape, + -concurrency-mt-unsafe, + -cppcoreguidelines-avoid-const-or-ref-data-members, + -cppcoreguidelines-avoid-do-while, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-avoid-non-const-global-variables + -cppcoreguidelines-non-private-member-variables-in-classes, + -cppcoreguidelines-pro-bounds-constant-array-index, + -fuchsia-default-arguments-calls, + -fuchsia-default-arguments-declarations, + -fuchsia-statically-constructed-objects, + -fuchsia-virtual-inheritance, + -google-global-names-in-headers, + -hicpp-named-parameter, + -hicpp-use-auto, + -llvm-header-guard, + -llvm-include-order, + -llvmlibc-*, + -misc-no-recursion, + -misc-non-private-member-variables-in-classes, + -misc-use-anonymous-namespace, + -readability-delete-null-pointer, + -readability-function-cognitive-complexity, + -readability-convert-member-functions-to-static, + -readability-identifier-length, + -readability-magic-numbers, + -readability-named-parameter, + -readability-simplify-boolean-expr, + -cppcoreguidelines-special-member-functions, + -hicpp-special-member-functions, + -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cppcoreguidelines-owning-memory, + ' WarningsAsErrors: '' HeaderFilterRegex: '' AnalyzeTemporaryDtors: false diff --git a/benchmarks/C++/build.sh b/benchmarks/C++/build.sh index 923f082f..e39eceab 100755 --- a/benchmarks/C++/build.sh +++ b/benchmarks/C++/build.sh @@ -3,7 +3,7 @@ if [ "$1" = "format" ] then CMD=clang-format type -P "$CMD" || CMD=clang-format-mp-16 - $CMD -i --style=file src/*.cpp src/*.h + $CMD -i --style=file src/*.cpp src/*.h src/**/*.cpp src/**/*.h exit 0 fi @@ -11,7 +11,7 @@ if [ "$1" = "check-format" ] then CMD=clang-format type -P "$CMD" || CMD=clang-format-mp-16 - $CMD --style=file --dry-run --Werror src/*.cpp src/*.h + $CMD --style=file --dry-run --Werror src/*.cpp src/*.h src/**/*.cpp src/**/*.h exit 0 fi @@ -23,4 +23,13 @@ then exit 0 fi -clang++-mp-16 -Wall -Wextra -O2 -ffp-contract=off -std=c++17 src/harness.cpp -o harness +if [ "$1" = "sanitize" ] +then + SANATIZE='-g -fsanitize=leak' + OPT='-Og' +else + SANATIZE='' + OPT='-O3' +fi + +clang++-mp-16 -Wall -Wextra $SANATIZE $OPT -ffp-contract=off -std=c++17 src/harness.cpp src/deltablue.cpp -o harness diff --git a/benchmarks/C++/src/benchmark.h b/benchmarks/C++/src/benchmark.h index 71be1860..5c12762f 100644 --- a/benchmarks/C++/src/benchmark.h +++ b/benchmarks/C++/src/benchmark.h @@ -1,5 +1,7 @@ #pragma once +#include + class Benchmark { public: virtual ~Benchmark() = default; @@ -8,7 +10,7 @@ class Benchmark { virtual bool verify_result(void* result) = 0; virtual bool inner_benchmark_loop(int32_t inner_iterations) { - for (int32_t i = 0; i < inner_iterations; i++) { + for (int32_t i = 0; i < inner_iterations; i += 1) { if (!verify_result(benchmark())) { return false; } diff --git a/benchmarks/C++/src/deltablue.cpp b/benchmarks/C++/src/deltablue.cpp new file mode 100644 index 00000000..b94c120a --- /dev/null +++ b/benchmarks/C++/src/deltablue.cpp @@ -0,0 +1,102 @@ +#include "deltablue.h" + +// Set static member variable +const Sym Strength::ABSOLUTE_STRONGEST(0); +const Sym Strength::REQUIRED(1); +const Sym Strength::STRONG_PREFERRED(2); +const Sym Strength::PREFERRED(3); +const Sym Strength::STRONG_DEFAULT(4); +const Sym Strength::DEFAULT(5); +const Sym Strength::WEAK_DEFAULT(6); +const Sym Strength::ABSOLUTE_WEAKEST(7); + +IdentityDictionary* Strength::_strengthTable; +IdentityDictionary* Strength::_strengthConstant; +const Strength* Strength::_absoluteWeakest; +const Strength* Strength::_required; + +const Strength* Strength::absoluteWeakest() { + return _absoluteWeakest; +} + +const Strength* Strength::required() { + return _required; +} + +IdentityDictionary* Strength::createStrengthTable() { + auto* strengthTable = new IdentityDictionary(); + strengthTable->atPut(&Strength::ABSOLUTE_STRONGEST, -10000); + strengthTable->atPut(&Strength::REQUIRED, -800); + strengthTable->atPut(&Strength::STRONG_PREFERRED, -600); + strengthTable->atPut(&Strength::PREFERRED, -400); + strengthTable->atPut(&Strength::STRONG_DEFAULT, -200); + strengthTable->atPut(&Strength::DEFAULT, 0); + strengthTable->atPut(&Strength::WEAK_DEFAULT, 500); + strengthTable->atPut(&Strength::ABSOLUTE_WEAKEST, 10000); + return strengthTable; +} + +IdentityDictionary* Strength::createStrengthConstants() { + auto* strengthConstant = new IdentityDictionary(); + _strengthTable->getKeys()->forEach( + [&strengthConstant](const CustomHash* const key) -> void { + const Sym* keySym = dynamic_cast(key); + strengthConstant->atPut(keySym, new Strength(keySym)); + }); + + return strengthConstant; +} + +void Strength::initializeConstants() { + _strengthTable = createStrengthTable(); + _strengthConstant = createStrengthConstants(); + _absoluteWeakest = of(&Strength::ABSOLUTE_WEAKEST); + _required = of(&Strength::REQUIRED); +} + +void AbstractConstraint::addConstraint(Planner* planner) { + addToGraph(); + planner->incrementalAdd(this); +} + +void AbstractConstraint::destroyConstraint(Planner* planner) { + if (isSatisfied()) { + planner->incrementalRemove(this); + } + removeFromGraph(); +} + +bool AbstractConstraint::inputsKnown(int32_t mark) { + return !inputsHasOne([mark](Variable* v) -> bool { + return !(v->getMark() == mark || v->getStay() || + v->getDeterminedBy() == nullptr); + }); +} + +AbstractConstraint* AbstractConstraint::satisfy(int32_t mark, + Planner* planner) { + AbstractConstraint* overridden = nullptr; + + chooseMethod(mark); + + if (isSatisfied()) { + inputsDo([mark](Variable* in) -> void { in->setMark(mark); }); + + Variable* out = getOutput(); + overridden = out->getDeterminedBy(); + if (overridden != nullptr) { + overridden->markUnsatisfied(); + } + out->setDeterminedBy(this); + if (!planner->addPropagate(this, mark)) { + throw Error("Cycle encountered"); + } + out->setMark(mark); + } else { + overridden = nullptr; + if (_strength->sameAs(Strength::required())) { + throw Error("Could not satisfy a required constraint"); + } + } + return overridden; +} diff --git a/benchmarks/C++/src/deltablue.h b/benchmarks/C++/src/deltablue.h new file mode 100644 index 00000000..bc42260d --- /dev/null +++ b/benchmarks/C++/src/deltablue.h @@ -0,0 +1,712 @@ +#pragma once + +#include "benchmark.h" +#include "som/error.h" +#include "som/identity_dictionary.h" +#include "som/vector.h" + +enum Direction { FORWARD, BACKWARD, NONE }; + +class Sym : public CustomHash { + private: + int32_t hash; + + public: + explicit constexpr Sym(int32_t hash_value) noexcept : hash(hash_value){}; + ~Sym() override = default; + + [[nodiscard]] int32_t customHash() const override { return hash; }; +}; + +class Strength { + public: + static const Sym ABSOLUTE_STRONGEST; + static const Sym REQUIRED; + static const Sym STRONG_PREFERRED; + static const Sym PREFERRED; + static const Sym STRONG_DEFAULT; + static const Sym DEFAULT; + static const Sym WEAK_DEFAULT; + static const Sym ABSOLUTE_WEAKEST; + + private: + int32_t const _arithmeticValue; + const Sym* const _symbolicValue; + + static IdentityDictionary* createStrengthTable(); + static IdentityDictionary* createStrengthConstants(); + + public: + explicit Strength(const Sym* const symbolicValue) + : _arithmeticValue(_strengthTable->at(symbolicValue)), + _symbolicValue(symbolicValue) {} + + bool sameAs(const Strength* const s) const { + return _arithmeticValue == s->_arithmeticValue; + } + + bool stronger(const Strength* const s) const { + return _arithmeticValue < s->_arithmeticValue; + } + + bool weaker(const Strength* const s) const { + return _arithmeticValue > s->_arithmeticValue; + } + + const Strength* strongest(const Strength* const s) const { + return s->stronger(this) ? s : this; + } + + const Strength* weakest(const Strength* const s) const { + return s->weaker(this) ? s : this; + } + + [[nodiscard]] int32_t getArithmeticValue() const { return _arithmeticValue; } + + static const Strength* of(const Sym* const strength) { + return _strengthConstant->atPtr(strength); + } + static const Strength* absoluteWeakest(); + static const Strength* required(); + static void initializeConstants(); + + private: + static const Strength* _absoluteWeakest; + static const Strength* _required; + + static IdentityDictionary* _strengthTable; + static IdentityDictionary* _strengthConstant; +}; + +class Planner; +class Variable; + +class AbstractConstraint { + protected: + const Strength* const _strength; + Planner* const _planer{nullptr}; + + public: + explicit AbstractConstraint(const Sym* strength) + : _strength(Strength::of(strength)) {} + + virtual ~AbstractConstraint() = default; + + [[nodiscard]] const Strength* getStrength() { return _strength; } + + virtual bool isInput() { return false; } + void addConstraint(Planner* planner); + void destroyConstraint(Planner* planner); + bool inputsKnown(int32_t mark); + AbstractConstraint* satisfy(int32_t mark, Planner* planner); + + virtual bool isSatisfied() = 0; + virtual void addToGraph() = 0; + virtual void removeFromGraph() = 0; + virtual Direction chooseMethod(int32_t mark) = 0; + virtual void execute() = 0; + virtual void inputsDo(std::function fn) = 0; + virtual bool inputsHasOne(std::function fn) = 0; + virtual void markUnsatisfied() = 0; + virtual Variable* getOutput() = 0; + virtual void recalculate() = 0; +}; + +class Variable { + private: + int32_t _value{0}; + Vector* _constraints; + AbstractConstraint* _determinedBy{nullptr}; + int32_t _mark{0}; + const Strength* _walkStrength; + bool _stay{true}; + + public: + Variable() + : _constraints(new Vector(2)), + _walkStrength(Strength::absoluteWeakest()) {} + + ~Variable() { delete _constraints; } + + static Variable* value(int32_t aValue) { + auto* v = new Variable(); + v->setValue(aValue); + return v; + } + + void addConstraint(AbstractConstraint* c) { _constraints->append(c); } + + [[nodiscard]] Vector* getConstraints() const { + return _constraints; + } + + [[nodiscard]] AbstractConstraint* getDeterminedBy() const { + return _determinedBy; + } + + void setDeterminedBy(AbstractConstraint* c) { _determinedBy = c; } + + [[nodiscard]] int32_t getMark() const { return _mark; } + + void setMark(int32_t markValue) { _mark = markValue; } + + void removeConstraint(AbstractConstraint* c) { + _constraints->remove(c); + if (_determinedBy == c) { + _determinedBy = nullptr; + } + } + + [[nodiscard]] bool getStay() const { return _stay; } + void setStay(bool v) { _stay = v; } + + [[nodiscard]] int32_t getValue() const { return _value; } + + void setValue(int32_t value) { _value = value; } + + [[nodiscard]] const Strength* getWalkStrength() const { + return _walkStrength; + } + + void setWalkStrength(const Strength* strength) { _walkStrength = strength; } +}; + +class BinaryConstraint : public AbstractConstraint { + protected: + Variable* _v1; + Variable* _v2; + Direction _direction{NONE}; + + public: + BinaryConstraint(Variable* var1, + Variable* var2, + const Sym* strength, + Planner*) + : AbstractConstraint(strength), _v1(var1), _v2(var2) {} + + // can't free _v1 and _v2 here, + // because they are shared with other constraints + ~BinaryConstraint() override = default; + + bool isSatisfied() override { return _direction != NONE; } + + void addToGraph() override { + _v1->addConstraint(this); + _v2->addConstraint(this); + _direction = NONE; + } + + void removeFromGraph() override { + _v1->removeConstraint(this); + _v2->removeConstraint(this); + _direction = NONE; + } + + Direction chooseMethod(int32_t mark) override { + if (_v1->getMark() == mark) { + if (_v2->getMark() != mark && + _strength->stronger(_v2->getWalkStrength())) { + _direction = FORWARD; + return _direction; + } + + _direction = NONE; + return _direction; + } + + if (_v2->getMark() == mark) { + if (_v1->getMark() != mark && + _strength->stronger(_v1->getWalkStrength())) { + _direction = BACKWARD; + return _direction; + } + + _direction = NONE; + return _direction; + } + + if (_v1->getWalkStrength()->weaker(_v2->getWalkStrength())) { + if (_strength->stronger(_v1->getWalkStrength())) { + _direction = BACKWARD; + return _direction; + } + + _direction = NONE; + return _direction; + } + + if (_strength->stronger(_v2->getWalkStrength())) { + _direction = FORWARD; + return _direction; + } + + _direction = NONE; + return _direction; + } + + void inputsDo(std::function fn) override { + if (_direction == FORWARD) { + fn(_v1); + } else { + fn(_v2); + } + } + + bool inputsHasOne(std::function fn) override { + if (_direction == FORWARD) { + return fn(_v1); + } + return fn(_v2); + } + + void markUnsatisfied() override { _direction = NONE; } + Variable* getOutput() override { return _direction == FORWARD ? _v2 : _v1; } + + void recalculate() override { + Variable* in = nullptr; + Variable* out = nullptr; + + if (_direction == FORWARD) { + in = _v1; + out = _v2; + } else { + in = _v2; + out = _v1; + } + + out->setWalkStrength(_strength->weakest(in->getWalkStrength())); + out->setStay(in->getStay()); + if (out->getStay()) { + execute(); + } + } +}; + +class UnaryConstraint : public AbstractConstraint { + protected: + Variable* _output; // possible output variable + bool _satisfied{false}; // true if I am currently satisfied + + public: + UnaryConstraint(Variable* v, const Sym* strength, Planner*) + : AbstractConstraint(strength), _output(v) { + // moved to subclass to avoid calling wrong method + // addConstraint(planner); + } + + // can't free _output here, because it is shared with other constraints + ~UnaryConstraint() override = default; + + bool isSatisfied() override { return _satisfied; }; + + void addToGraph() override { + _output->addConstraint(this); + _satisfied = false; + } + + void removeFromGraph() override { + if (_output != nullptr) { + _output->removeConstraint(this); + } + _satisfied = false; + } + + Direction chooseMethod(int32_t mark) override { + _satisfied = (_output->getMark() != mark) && + _strength->stronger(_output->getWalkStrength()); + return NONE; + } + + void inputsDo(std::function) override {} + + bool inputsHasOne(std::function) override { return false; } + + void markUnsatisfied() override { _satisfied = false; } + Variable* getOutput() override { return _output; } + + void recalculate() override { + _output->setWalkStrength(_strength); + _output->setStay(!isInput()); + if (_output->getStay()) { + execute(); + } + } +}; + +class EditConstraint : public UnaryConstraint { + public: + EditConstraint(Variable* v, const Sym* strength, Planner* planner) + : UnaryConstraint(v, strength, planner) { + addConstraint(planner); // moved here from UnaryConstraint constructor to + // make sure the right method is called + }; + + bool isInput() override { return true; } + + void execute() override { + // Edit constraints do nothing. + } +}; + +class EqualityConstraint : public BinaryConstraint { + public: + EqualityConstraint(Variable* var1, + Variable* var2, + const Sym* strength, + Planner* planner) + : BinaryConstraint(var1, var2, strength, planner) { + addConstraint(planner); + } + + void execute() override { + if (_direction == Direction::FORWARD) { + _v2->setValue(_v1->getValue()); + } else { + _v1->setValue(_v2->getValue()); + } + } +}; + +class Plan : public Vector { + public: + Plan() : Vector(15){}; + + void execute() { + forEach([&](AbstractConstraint* c) -> void { c->execute(); }); + } +}; + +class ScaleConstraint : public BinaryConstraint { + private: + Variable* _scale; + Variable* _offset; + + public: + ScaleConstraint(Variable* src, + Variable* scale, + Variable* offset, + Variable* dest, + const Sym* strength, + Planner* planner) + : BinaryConstraint(src, dest, strength, planner), + _scale(scale), + _offset(offset) { + addConstraint(planner); + } + + void addToGraph() override { + _v1->addConstraint(this); + _v2->addConstraint(this); + _scale->addConstraint(this); + _offset->addConstraint(this); + _direction = NONE; + } + + void removeFromGraph() override { + if (_v1 != nullptr) { + _v1->removeConstraint(this); + } + if (_v2 != nullptr) { + _v2->removeConstraint(this); + } + if (_scale != nullptr) { + _scale->removeConstraint(this); + } + if (_offset != nullptr) { + _offset->removeConstraint(this); + } + _direction = NONE; + } + + void execute() override { + if (_direction == FORWARD) { + _v2->setValue(_v1->getValue() * _scale->getValue() + _offset->getValue()); + } else { + _v1->setValue((_v2->getValue() - _offset->getValue()) / + _scale->getValue()); + } + } + + void inputsDo(std::function fn) override { + if (_direction == FORWARD) { + fn(_v1); + fn(_scale); + fn(_offset); + } else { + fn(_v2); + fn(_scale); + fn(_offset); + } + } + void recalculate() override { + Variable* in = nullptr; + Variable* out = nullptr; + + if (_direction == FORWARD) { + in = _v1; + out = _v2; + } else { + out = _v1; + in = _v2; + } + + out->setWalkStrength(_strength->weakest(in->getWalkStrength())); + out->setStay(in->getStay() && _scale->getStay() && _offset->getStay()); + if (out->getStay()) { + execute(); // stay optimization + } + } +}; + +class StayConstraint : public UnaryConstraint { + public: + StayConstraint(Variable* v, const Sym* strength, Planner* planner) + : UnaryConstraint(v, strength, planner) { + addConstraint(planner); // moved here from UnaryConstraint constructor to + // make sure the right method is called + }; + + void execute() override { + // StayConstraints do nothing. + } +}; + +class Planner { + private: + int32_t _currentMark{1}; + + public: + Planner() = default; + + void incrementalAdd(AbstractConstraint* c) { + const int32_t mark = newMark(); + AbstractConstraint* overridden = c->satisfy(mark, this); + + while (overridden != nullptr) { + overridden = overridden->satisfy(mark, this); + } + } + + void incrementalRemove(AbstractConstraint* c) { + Variable* out = c->getOutput(); + c->markUnsatisfied(); + c->removeFromGraph(); + + Vector* unsatisfied = removePropagateFrom(out); + unsatisfied->forEach( + [this](AbstractConstraint* u) -> void { incrementalAdd(u); }); + delete unsatisfied; + } + + Plan* extractPlanFromConstraints(Vector* constraints) { + Vector sources = Vector(); + constraints->forEach([&](AbstractConstraint* c) -> void { + if (c->isInput() && c->isSatisfied()) { + sources.append(c); + } + }); + return makePlan(&sources); + } + + Plan* makePlan(Vector* sources) { + const int32_t mark = newMark(); + Plan* plan = new Plan(); + Vector* todo = sources; + + while (!todo->isEmpty()) { + AbstractConstraint* c = todo->removeFirst(); + + if (c->getOutput()->getMark() != mark && c->inputsKnown(mark)) { + plan->append(c); + c->getOutput()->setMark(mark); + addConstraintsConsumingTo(c->getOutput(), todo); + } + } + + return plan; + } + + void addConstraintsConsumingTo(Variable* v, + Vector* coll) { + AbstractConstraint* determiningC = v->getDeterminedBy(); + + v->getConstraints()->forEach( + [&coll, determiningC](AbstractConstraint* c) -> void { + if (c != determiningC && c->isSatisfied()) { + coll->append(c); + } + }); + } + + bool addPropagate(AbstractConstraint* c, int32_t mark) { + Vector* todo = Vector::with(c); + + while (!todo->isEmpty()) { + AbstractConstraint* d = todo->removeFirst(); + + if (d->getOutput()->getMark() == mark) { + incrementalRemove(c); + delete todo; + return false; + } + + d->recalculate(); + addConstraintsConsumingTo(d->getOutput(), todo); + } + + delete todo; + return true; + } + + void change(Variable* var, int32_t newValue) { + auto* editC = new EditConstraint(var, &Strength::PREFERRED, this); + auto* editV = Vector::with(editC); + Plan* plan = extractPlanFromConstraints(editV); + + for (int32_t i = 0; i < 10; i += 1) { + var->setValue(newValue); + plan->execute(); + } + + editC->destroyConstraint(this); + delete plan; + delete editV; + } + + void constraintsConsuming(Variable* v, + std::function fn) { + AbstractConstraint* determiningC = v->getDeterminedBy(); + + v->getConstraints()->forEach([&](AbstractConstraint* c) -> void { + if (c != determiningC && c->isSatisfied()) { + fn(c); + } + }); + } + + int32_t newMark() { + _currentMark += 1; + return _currentMark; + } + + Vector* removePropagateFrom(Variable* out) { + auto* unsatisfied = new Vector(); + + out->setDeterminedBy(nullptr); + out->setWalkStrength(Strength::absoluteWeakest()); + out->setStay(true); + + auto* todo = Vector::with(out); + + while (!todo->isEmpty()) { + Variable* v = todo->removeFirst(); + + v->getConstraints()->forEach( + [unsatisfied](AbstractConstraint* c) -> void { + if (!c->isSatisfied()) { + unsatisfied->append(c); + } + }); + + constraintsConsuming(v, [&todo](AbstractConstraint* c) -> void { + c->recalculate(); + todo->append(c->getOutput()); + }); + } + delete todo; + + unsatisfied->sort( + [](AbstractConstraint* c1, AbstractConstraint* c2) -> int32_t { + return c1->getStrength()->stronger(c2->getStrength()) ? -1 : 1; + }); + + return unsatisfied; + } + + static void chainTest(int32_t n) { + Strength::initializeConstants(); + Planner planner = Planner(); + auto* vars = new Variable*[n + 1]; + for (int32_t i = 0; i < n + 1; i += 1) { + vars[i] = new Variable(); + } + for (int32_t i = 0; i < n; i += 1) { + Variable* v1 = vars[i]; + Variable* v2 = vars[i + 1]; + new EqualityConstraint(v1, v2, &Strength::REQUIRED, &planner); + } + new StayConstraint(vars[n], &Strength::STRONG_DEFAULT, &planner); + + auto* editC = new EditConstraint(vars[0], &Strength::PREFERRED, &planner); + auto* editV = Vector::with(editC); + Plan* plan = planner.extractPlanFromConstraints(editV); + delete editV; + + for (int i = 0; i < 100; i++) { + vars[0]->setValue(i); + plan->execute(); + if (vars[n]->getValue() != i) { + throw Error("Chain test failed!"); + } + } + editC->destroyConstraint(&planner); + delete plan; + delete[] vars; + } + + static void projectionTest(int32_t n) { + Planner planner = Planner(); + Vector dests = Vector(); + + Variable* scale = Variable::value(10); + Variable* offset = Variable::value(1000); + + Variable* src = nullptr; + Variable* dst = nullptr; + for (int32_t i = 1; i <= n; i++) { + src = Variable::value(i); + dst = Variable::value(i); + dests.append(dst); + new StayConstraint(src, &Strength::DEFAULT, &planner); + new ScaleConstraint(src, scale, offset, dst, &Strength::REQUIRED, + &planner); + } + + planner.change(src, 17); + if (dst->getValue() != 1170) { + throw Error("Projection test 1 failed!"); + } + + planner.change(dst, 1050); + if (src->getValue() != 5) { + throw Error("Projection test 2 failed!"); + } + + planner.change(scale, 5); + for (int32_t i = 0; i < n - 1; ++i) { + if (dests.at(i)->getValue() != (i + 1) * 5 + 1000) { + throw Error("Projection test 3 failed!"); + } + } + + planner.change(offset, 2000); + for (int32_t i = 0; i < n - 1; ++i) { + if (dests.at(i)->getValue() != (i + 1) * 5 + 2000) { + throw Error("Projection test 4 failed!"); + } + } + } +}; + +class DeltaBlue : public Benchmark { + public: + bool inner_benchmark_loop(int32_t innerIterations) override { + Planner::chainTest(innerIterations); + Planner::projectionTest(innerIterations); + return true; + } + + void* benchmark() override { return nullptr; } + + bool verify_result(void*) override { return false; } +}; diff --git a/benchmarks/C++/src/deltablue/AbstractConstraint.cpp b/benchmarks/C++/src/deltablue/AbstractConstraint.cpp deleted file mode 100644 index 3746f882..00000000 --- a/benchmarks/C++/src/deltablue/AbstractConstraint.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "Planner.h" - -using namespace std; - -namespace deltablue { - - AbstractConstraint::AbstractConstraint(shared_ptr strength) { - _strength = Strength::of(strength); - } - - shared_ptr AbstractConstraint::getStrength() { - return _strength; - } - - bool AbstractConstraint::isInput() { - return false; - } - - void AbstractConstraint::addConstraint(shared_ptr planner) { - addToGraph(); - planner->incrementalAdd(shared_from_this()); - } - - - void AbstractConstraint::destroyConstraint(shared_ptr planner) { - if (isSatisfied()) { - planner->incrementalRemove(shared_from_this()); - } - removeFromGraph(); - } - - bool AbstractConstraint::inputsKnown(int mark) { - return !inputsHasOne([&mark](shared_ptr v) -> bool { - return !(v->getMark() == mark || v->getStay() || v->getDeterminedBy() == nullptr); - }); - } - - shared_ptr AbstractConstraint::satisfy(int mark, shared_ptr planner) { - shared_ptr overridden; - - chooseMethod(mark); - - if (isSatisfied()) { - - inputsDo([&mark](shared_ptr in) -> void { - in->setMark(mark); - }); - - shared_ptr out = getOutput(); - overridden = out->getDeterminedBy(); - if (overridden != nullptr) { - overridden->markUnsatisfied(); - } - out->setDeterminedBy(shared_from_this()); - if (!planner->addPropagate(shared_from_this(), mark)) { - throw Error("Cycle encountered"); - } - out->setMark(mark); - } else { - overridden = nullptr; - if (_strength->sameAs(Strength::required())) { - throw Error("Could not satisfy a required constraint"); - } - } - return overridden; - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/AbstractConstraint.h b/benchmarks/C++/src/deltablue/AbstractConstraint.h deleted file mode 100644 index 557b25b6..00000000 --- a/benchmarks/C++/src/deltablue/AbstractConstraint.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef ABSTRACTCONSTRAINT -#define ABSTRACTCONSTRAINT - -#include -#include -#include -#include "../som/Error.cpp" -#include "Variable.h" -#include "Direction.h" - -using namespace std; - -namespace deltablue { - - class Planner; - - class AbstractConstraint : public enable_shared_from_this { - protected: - shared_ptr _strength; - shared_ptr _planer; - public: - - - AbstractConstraint(shared_ptr strength); - - shared_ptr getStrength(); - virtual bool isInput(); - void addConstraint(shared_ptr planner); - void destroyConstraint(shared_ptr planner); - bool inputsKnown(int mark); - shared_ptr satisfy(int mark, shared_ptr planner); - - virtual bool isSatisfied() {}; - virtual void addToGraph() {}; - virtual void removeFromGraph() {}; - virtual Direction chooseMethod(int mark) {}; - virtual void execute() {}; - virtual void inputsDo(function)> fn) {}; - virtual bool inputsHasOne(function )> fn) {}; - virtual void markUnsatisfied() {}; - virtual shared_ptr getOutput() {}; - virtual void recalculate() {}; - - - }; -} - -#endif //ABSTRACTCONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/BinaryConstraint.cpp b/benchmarks/C++/src/deltablue/BinaryConstraint.cpp deleted file mode 100644 index 75a7face..00000000 --- a/benchmarks/C++/src/deltablue/BinaryConstraint.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "BinaryConstraint.h" - -namespace deltablue { - - BinaryConstraint::BinaryConstraint(shared_ptr var1, shared_ptr var2, - shared_ptr strength/*, shared_ptr planner*/) : AbstractConstraint(strength) { /// don't use planner ??? Probleme with "this" - _v1 = var1; - _v2 = var2; - _direction = NONE; - } - - bool BinaryConstraint::isSatisfied() { - return _direction != NONE; - } - - void BinaryConstraint::addToGraph() { - _v1->addConstraint(shared_from_this()); - _v2->addConstraint(shared_from_this()); - _direction = NONE; - } - - void BinaryConstraint::removeFromGraph() { - _v1->removeConstraint(shared_from_this()); - _v2->removeConstraint(shared_from_this()); - _direction = NONE; - } - - Direction BinaryConstraint::chooseMethod(int mark) { - if (_v1->getMark() == mark) { - if (_v2->getMark() != mark && _strength->stronger(_v2->getWalkStrength())) { - _direction = FORWARD; - return _direction; - } else { - _direction = NONE; - return _direction; - } - } - - if (_v2->getMark() == mark) { - if (_v1->getMark() != mark && _strength->stronger(_v1->getWalkStrength())) { - _direction = BACKWARD; - return _direction; - } else { - _direction = NONE; - return _direction; - } - } - - if (_v1->getWalkStrength()->weaker(_v2->getWalkStrength())) { - if (_strength->stronger(_v1->getWalkStrength())) { - _direction = BACKWARD; - return _direction; - } else { - _direction = NONE; - return _direction; - } - } else { - if (_strength->stronger(_v2->getWalkStrength())) { - _direction = FORWARD; - return _direction; - } else { - _direction = NONE; - return _direction; - } - } - } - - void BinaryConstraint::inputsDo(function)> fn) { - if (_direction == FORWARD) { - fn(_v1); - } else { - fn(_v2); - } - } - - bool BinaryConstraint::inputsHasOne(function)> fn) { - if (_direction == FORWARD) { - return fn(_v1); - } else { - return fn(_v2); - } - } - - void BinaryConstraint::markUnsatisfied() { - _direction = NONE; - } - - shared_ptr BinaryConstraint::getOutput() { - return _direction == FORWARD ? _v2 : _v1; - } - - void BinaryConstraint::recalculate() { - shared_ptr in; - shared_ptr out; - - if (_direction == FORWARD) { - in = _v1; - out = _v2; - } else { - in = _v2; - out = _v1; - } - - out->setWalkStrength(_strength->weakest(in->getWalkStrength())); - out->setStay(in->getStay()); - if (out->getStay()) { - execute(); - } - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/BinaryConstraint.h b/benchmarks/C++/src/deltablue/BinaryConstraint.h deleted file mode 100644 index 23ad3ba4..00000000 --- a/benchmarks/C++/src/deltablue/BinaryConstraint.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef BINARYCONSTRAINT -#define BINARYCONSTRAINT - -#include "AbstractConstraint.h" - -using namespace std; - -namespace deltablue { - class BinaryConstraint: public AbstractConstraint { - protected: - shared_ptr _v1; - shared_ptr _v2; - Direction _direction; - - public: - BinaryConstraint(shared_ptr var1, shared_ptr var2, shared_ptr strength/*, shared_ptr planner*/); - bool isSatisfied() override; - void addToGraph() override; - void removeFromGraph() override; - Direction chooseMethod(int mark) override; - void inputsDo(function)> fn) override; - bool inputsHasOne(function)> fn) override; - void markUnsatisfied() override; - shared_ptr getOutput() override; - void recalculate() override ; - }; -} -#endif //BINARYCONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Direction.h b/benchmarks/C++/src/deltablue/Direction.h deleted file mode 100644 index 9a72ac7d..00000000 --- a/benchmarks/C++/src/deltablue/Direction.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef DIRECTION -#define DIRECTION - -namespace deltablue { - enum Direction { - FORWARD, BACKWARD, NONE - }; -} - -#endif //DIRECTION \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/EditConstraint.cpp b/benchmarks/C++/src/deltablue/EditConstraint.cpp deleted file mode 100644 index d8a0bf44..00000000 --- a/benchmarks/C++/src/deltablue/EditConstraint.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "EditConstraint.h" - -namespace deltablue { - EditConstraint::EditConstraint(shared_ptr v, shared_ptr strength, shared_ptr planner) - : UnaryConstraint(v, strength, planner) { - } - - bool EditConstraint::isInput() { - return true; - } - - void EditConstraint::execute() { - // Edit constraints do nothing. - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/EditConstraint.h b/benchmarks/C++/src/deltablue/EditConstraint.h deleted file mode 100644 index e3d57ef7..00000000 --- a/benchmarks/C++/src/deltablue/EditConstraint.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef EDITCONSTRAINT -#define EDITCONSTRAINT - -#include -#include "Planner.h" -#include "UnaryConstraint.h" - -using namespace std; - -namespace deltablue { - - class EditConstraint: public UnaryConstraint { - public: - - EditConstraint(shared_ptr v, shared_ptr strength, shared_ptr planner); - - bool isInput() override; - void execute() override; - }; -} - -#endif //EDITCONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/EqualityConstraint.cpp b/benchmarks/C++/src/deltablue/EqualityConstraint.cpp deleted file mode 100644 index b5ff7db4..00000000 --- a/benchmarks/C++/src/deltablue/EqualityConstraint.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "EqualityConstraint.h" - -namespace deltablue { - EqualityConstraint::EqualityConstraint(shared_ptr var1, shared_ptr var2, shared_ptr strength, shared_ptr planner) - : BinaryConstraint(var1, var2, strength/*, planner*/) { - //addConstraint(planner); - } - - void EqualityConstraint::execute() { - if (_direction == Direction::FORWARD) { - _v2->setValue(_v1->getValue()); - } else { - _v1->setValue(_v2->getValue()); - } - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/EqualityConstraint.h b/benchmarks/C++/src/deltablue/EqualityConstraint.h deleted file mode 100644 index db106587..00000000 --- a/benchmarks/C++/src/deltablue/EqualityConstraint.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef EQUALITYCONSTRAINT -#define EQUALITYCONSTRAINT - -#include "BinaryConstraint.h" -#include "Strength.h" -#include "Direction.h" -#include - -using namespace std; - -namespace deltablue { - class EqualityConstraint : public BinaryConstraint { - public: - EqualityConstraint(shared_ptr var1, shared_ptr var2, shared_ptr strength, shared_ptr planner); - - void execute() override; - }; -} - -#endif //EQUALITYCONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Plan.cpp b/benchmarks/C++/src/deltablue/Plan.cpp deleted file mode 100644 index 2198940e..00000000 --- a/benchmarks/C++/src/deltablue/Plan.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "Plan.h" - -using namespace std; - -namespace deltablue { - - Plan::Plan() : Vector>() {} - - void Plan::execute() { - forEach([&](shared_ptr c) -> void { - c->execute(); - }); - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Plan.h b/benchmarks/C++/src/deltablue/Plan.h deleted file mode 100644 index 4b836723..00000000 --- a/benchmarks/C++/src/deltablue/Plan.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef PLAN -#define PLAN - -#include "AbstractConstraint.h" -#include "../som/Vector.cpp" - -using namespace std; - -namespace deltablue { - - class Plan : public Vector> { - public: - Plan(); - - void execute(); - }; -} - -#endif //PLAN \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Planner.cpp b/benchmarks/C++/src/deltablue/Planner.cpp deleted file mode 100644 index 480c6017..00000000 --- a/benchmarks/C++/src/deltablue/Planner.cpp +++ /dev/null @@ -1,230 +0,0 @@ -#include "Planner.h" -#include - -using namespace std; - -namespace deltablue { - - Planner::Planner() { - _currentMark = 1; - } - - void Planner::incrementalAdd(shared_ptr c) { - int mark = newMark(); - shared_ptr overridden = c->satisfy(mark, shared_ptr()); - - while (overridden != nullptr) { - overridden = overridden->satisfy(mark, shared_ptr()); - } - } - - void Planner::incrementalRemove(shared_ptr c) { - shared_ptr out = c->getOutput(); - c->markUnsatisfied(); - c->removeFromGraph(); - - shared_ptr>> unsatisfied = removePropagateFrom(out); - unsatisfied->forEach([&](shared_ptr u) -> void { - incrementalAdd(u); - }); - } - - shared_ptr Planner::extractPlanFromConstraints(shared_ptr>> constraints) { - shared_ptr>> sources = make_shared>>(); - constraints->forEach([&](shared_ptr c) -> void { - if (c->isInput() && c->isSatisfied()) { - sources->append(c); - } - }); - return makePlan(sources); - } - - shared_ptr Planner::makePlan(shared_ptr>> sources) { - int mark = newMark(); - shared_ptr plan = make_shared(); - shared_ptr>> todo = sources; - - while (!todo->isEmpty()) { - shared_ptr c = todo->removeFirst(); - - if (c->getOutput()->getMark() != mark && c->inputsKnown(mark)) { - plan->append(c); - c->getOutput()->setMark(mark); - addConstraintsConsumingTo(c->getOutput(), todo); - } - } - - return plan; - } - - void Planner::propagateFrom(shared_ptr v) { - shared_ptr>> todo = make_shared>>(); - addConstraintsConsumingTo(v, todo); - - while (!todo->isEmpty()) { - shared_ptr c = todo->removeFirst(); - c->execute(); - addConstraintsConsumingTo(c->getOutput(), todo); - } - } - - void Planner::addConstraintsConsumingTo(shared_ptr v, shared_ptr>> coll) { - shared_ptr determiningC = v->getDeterminedBy(); - - v->getConstraints()->forEach([&](shared_ptr c) -> void { - if (c != determiningC && c->isSatisfied()) { - coll->append(c); - } - }); - } - - bool Planner::addPropagate(shared_ptr c, int mark) { - shared_ptr>> todo = Vector>::with(c); - - while (!todo->isEmpty()) { - shared_ptr d = todo->removeFirst(); - - if (d->getOutput()->getMark() == mark) { - incrementalRemove(c); - return false; - } - - d->recalculate(); - addConstraintsConsumingTo(d->getOutput(), todo); - } - - return true; - } - - void Planner::change(shared_ptr var, int newValue) { - shared_ptr editC = make_shared(var, Strength::PREFERRED, shared_from_this()); - editC->addConstraint(shared_from_this()); - - shared_ptr>> editV = Vector>::with(editC); - shared_ptr plan = extractPlanFromConstraints(editV); - for (int i = 0; i < 10; i++) { - var->setValue(newValue); - plan->execute(); - } - - editC->destroyConstraint(shared_from_this()); - } - - void Planner::constraintsConsuming(shared_ptr v, function)> fn) { - shared_ptr determiningC = v->getDeterminedBy(); - - v->getConstraints()->forEach([&](shared_ptr c) -> void { - if (c != determiningC && c->isSatisfied()) { - fn(c); - } - }); - } - - int Planner::newMark() { - _currentMark++; - return _currentMark; - } - - shared_ptr>> Planner::removePropagateFrom(shared_ptr out) { - shared_ptr>> unsatisfied = make_shared>>(); - - out->setDeterminedBy(nullptr); - out->setWalkStrength(Strength::absoluteWeakest()); - out->setStay(true); - - shared_ptr>> todo = Vector>::with(out); - - while (!todo->isEmpty()) { - shared_ptr v = todo->removeFirst(); - - v->getConstraints()->forEach([&](shared_ptr c) -> void { - if (!c->isSatisfied()) { - unsatisfied->append(c); - } - }); - - constraintsConsuming(v, [&todo](shared_ptr c) -> void { - c->recalculate(); - todo->append(c->getOutput()); - }); - } - - unsatisfied->sort([&](shared_ptr c1, shared_ptr c2) -> int { - return c1->getStrength()->stronger(c2->getStrength()) ? -1 : 1; - - }); - - return unsatisfied; - } - - void Planner::chainTest(int n) { - Strength::initializeConstants(); - shared_ptr planner = make_shared(); - shared_ptr* vars = new shared_ptr[n + 1]; - for (int i = 0; i < n + 1; i++) { - vars[i] = make_shared(); - } - for (int i = 0; i < n; i++) { - shared_ptr v1 = vars[i]; - shared_ptr v2 = vars[i + 1]; - (make_shared(v1, v2, Strength::REQUIRED, planner))->addConstraint(planner); - } - (make_shared(vars[n], Strength::STRONG_DEFAULT, planner))->addConstraint(planner); - shared_ptr editC = make_shared(vars[0], Strength::PREFERRED, planner); - editC->addConstraint(planner); - shared_ptr>> editV = Vector>::with(editC); - shared_ptr plan = planner->extractPlanFromConstraints(editV); - - for (int i = 0; i < 100; i++) { - vars[0]->setValue(i); - plan->execute(); - if (vars[n]->getValue() != i) { - throw Error("Chain test failed!"); - } - } - editC->destroyConstraint(planner); - } - - void Planner::projectionTest(int n) { - shared_ptr planner = make_shared(); - shared_ptr>> dests = make_shared>>(); - - shared_ptr scale = Variable::value(10); - shared_ptr offset = Variable::value(1000); - - shared_ptr src = nullptr; - shared_ptr dst = nullptr; - for (int i = 1; i <= n; i++) { - src = Variable::value(i); - dst = Variable::value(i); - dests->append(dst); - (make_shared(src, Strength::DEFAULT, planner))->addConstraint(planner); - (make_shared(src, scale, offset, dst, Strength::REQUIRED, planner))->addConstraint(planner); - } - - planner->change(src, 17); - if (dst->getValue() != 1170) { - throw Error("Projection test 1 failed!"); - } - - planner->change(dst, 1050); - if (src->getValue() != 5) { - throw Error("Projection test 2 failed!"); - - } - - planner->change(scale, 5); - for (int i = 0; i < n - 1; ++i) { - if (dests->at(i)->getValue() != (i + 1) * 5 + 1000) { - throw Error("Projection test 3 failed!"); - } - } - - planner->change(offset, 2000); - for (int i = 0; i < n - 1; ++i) { - if (dests->at(i)->getValue() != (i + 1) * 5 + 2000) { - throw Error("Projection test 4 failed!"); - } - } - } -} diff --git a/benchmarks/C++/src/deltablue/Planner.h b/benchmarks/C++/src/deltablue/Planner.h deleted file mode 100644 index 22868b91..00000000 --- a/benchmarks/C++/src/deltablue/Planner.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef PLANNER -#define PLANNER - -#include -#include -#include "AbstractConstraint.h" -#include "EqualityConstraint.h" -#include "ScaleConstraint.h" -#include "Plan.h" -#include "../som/Vector.cpp" -#include "StayConstraint.h" -#include "EditConstraint.h" - -using namespace std; - -namespace deltablue { - - class Planner : public enable_shared_from_this { - private: - int _currentMark; - - public: - Planner(); - - void incrementalAdd(shared_ptr c); - void incrementalRemove(shared_ptr c); - shared_ptr extractPlanFromConstraints(shared_ptr>> constraints); - shared_ptr makePlan(shared_ptr>> sources); - void propagateFrom(shared_ptr v); - void addConstraintsConsumingTo(shared_ptr v, shared_ptr>> coll); - bool addPropagate(shared_ptr c, int mark); - - void change(shared_ptr var, int newValue); - - void constraintsConsuming(shared_ptr v, function)> fn); - - int newMark(); - - shared_ptr>> removePropagateFrom(shared_ptr out); - - static void chainTest(int n); - static void projectionTest(int n); - }; -} - -#endif //PLANNER \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/ScaleConstraint.cpp b/benchmarks/C++/src/deltablue/ScaleConstraint.cpp deleted file mode 100644 index f054eb2f..00000000 --- a/benchmarks/C++/src/deltablue/ScaleConstraint.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "ScaleConstraint.h" - -namespace deltablue { - - ScaleConstraint::ScaleConstraint(shared_ptr src, shared_ptr scale, shared_ptr offset, - shared_ptr dest, shared_ptr strength, shared_ptr planner) - : BinaryConstraint(src, dest, strength/*, planner*/) { - _strength = Strength::of(strength); - _v1 = src; - _v2 = dest; - _direction = NONE; - _scale = scale; - _offset = offset; - - //addConstraint(planner); - } - - void ScaleConstraint::addToGraph() { - _v1->addConstraint(shared_from_this()); - _v2->addConstraint(shared_from_this()); - _scale->addConstraint(shared_from_this()); - _offset->addConstraint(shared_from_this()); - _direction = NONE; - } - - void ScaleConstraint::removeFromGraph() { - if (_v1 != nullptr) - _v1->removeConstraint(shared_from_this()); - if (_v2 != nullptr) - _v2->removeConstraint(shared_from_this()); - if (_scale != nullptr) - _scale->removeConstraint(shared_from_this()); - if (_offset != nullptr) - _offset->removeConstraint(shared_from_this()); - _direction = NONE; - } - - void ScaleConstraint::execute() { - if (_direction == FORWARD) { - _v2->setValue(_v1->getValue() * _scale->getValue() + _offset->getValue()); - } else { - _v1->setValue((_v2->getValue() - _offset->getValue()) / _scale->getValue()); - } - } - - void ScaleConstraint::inputsDo(function)> fn) { - if (_direction == FORWARD) { - fn(_v1); - fn(_scale); - fn(_offset); - } else { - fn(_v2); - fn(_scale); - fn(_offset); - } - } - - void ScaleConstraint::recalculate() { - shared_ptr in; - shared_ptr out; - - if (_direction == FORWARD) { - in = _v1; - out = _v2; - } else { - out = _v1; - in = _v2; - } - - out->setWalkStrength(_strength->weakest(in->getWalkStrength())); - out->setStay(in->getStay() && _scale->getStay() && _offset->getStay()); - if (out->getStay()) { - execute(); // stay optimization - } - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/ScaleConstraint.h b/benchmarks/C++/src/deltablue/ScaleConstraint.h deleted file mode 100644 index d9827c13..00000000 --- a/benchmarks/C++/src/deltablue/ScaleConstraint.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef SCALECONSTRAINT -#define SCALECONSTRAINT - - -#include "BinaryConstraint.h" -#include "Variable.h" -#include - -using namespace std; - -namespace deltablue { - class ScaleConstraint :public BinaryConstraint { - private: - shared_ptr _scale; - shared_ptr _offset; - - public: - ScaleConstraint(shared_ptr src, shared_ptr scale, shared_ptr offset, - shared_ptr dest, shared_ptr strength, shared_ptr planner); - - void addToGraph() override; - - void removeFromGraph() override; - void execute() override; - - void inputsDo(function)> fn) override; - void recalculate() override; - }; -} - -#endif //SCALECONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/StayConstraint.cpp b/benchmarks/C++/src/deltablue/StayConstraint.cpp deleted file mode 100644 index e2e719a6..00000000 --- a/benchmarks/C++/src/deltablue/StayConstraint.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "StayConstraint.h" - -using namespace std; - -namespace deltablue { - - StayConstraint::StayConstraint(shared_ptr v, shared_ptr strength, - shared_ptr planner) : UnaryConstraint(v, strength, planner) {} - - void StayConstraint::execute() {} -} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/StayConstraint.h b/benchmarks/C++/src/deltablue/StayConstraint.h deleted file mode 100644 index a72f4526..00000000 --- a/benchmarks/C++/src/deltablue/StayConstraint.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef STAYCONSTRAINT -#define STAYCONSTRAINT - -#include "UnaryConstraint.h" -#include "Planner.h" - -using namespace std; - -namespace deltablue { - - class StayConstraint : public UnaryConstraint { - public: - - StayConstraint(shared_ptr v, shared_ptr strength, - shared_ptr planner); - - void execute() override; - - }; -} - -#endif //STAYCONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Strength.cpp b/benchmarks/C++/src/deltablue/Strength.cpp deleted file mode 100644 index fc0d9eec..00000000 --- a/benchmarks/C++/src/deltablue/Strength.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "Strength.h" - -using namespace std; - -namespace deltablue { - - shared_ptr> Strength::_strengthTable; - shared_ptr>> Strength::_strengthConstant; - shared_ptr Strength::_absoluteWeakest; - shared_ptr Strength::_required; - - // Set static member variable - shared_ptr Strength::ABSOLUTE_STRONGEST = make_shared(0); - shared_ptr Strength::REQUIRED = make_shared(1); - shared_ptr Strength::STRONG_PREFERRED = make_shared(2); - shared_ptr Strength::PREFERRED = make_shared(3); - shared_ptr Strength::STRONG_DEFAULT = make_shared(4); - shared_ptr Strength::DEFAULT = make_shared(5); - shared_ptr Strength::WEAK_DEFAULT = make_shared(6); - shared_ptr Strength::ABSOLUTE_WEAKEST = make_shared(7); - - Strength::Sym::Sym(int hash) { - _hash = hash; - } - - int Strength::Sym::customHash() { - return _hash; - } - - Strength::Strength(shared_ptr symbolicValue) { - _symbolicValue = symbolicValue; - _arithmeticValue = _strengthTable->at(symbolicValue); - } - - - bool Strength::sameAs(shared_ptr s) const { - return _arithmeticValue == s->_arithmeticValue; - } - - bool Strength::stronger(shared_ptr s) const { - return _arithmeticValue < s->_arithmeticValue; - } - - bool Strength::weaker(shared_ptr s) const { - return _arithmeticValue > s->_arithmeticValue; - } - - shared_ptr Strength::strongest(shared_ptr s) { - return s->stronger(shared_from_this()) ? s : shared_from_this(); - } - - shared_ptr Strength::weakest(shared_ptr s) { - return s->weaker(shared_from_this()) ? s : shared_from_this(); - } - - int Strength::get_arithmeticValue() const { - return _arithmeticValue; - } - - shared_ptr Strength::of(shared_ptr strength) { - return _strengthConstant->atPtr(strength); - } - - shared_ptr Strength::absoluteWeakest() { - return _absoluteWeakest; - } - - shared_ptr Strength::required() { - return _required; - } - - shared_ptr> Strength::createStrengthTable() { - shared_ptr> strengthTable = make_shared>(); - strengthTable->atPut(Strength::ABSOLUTE_STRONGEST, -10000); - strengthTable->atPut(Strength::REQUIRED, -800); - strengthTable->atPut(Strength::STRONG_PREFERRED, -600); - strengthTable->atPut(Strength::PREFERRED, -400); - strengthTable->atPut(Strength::STRONG_DEFAULT, -200); - strengthTable->atPut(Strength::DEFAULT, 0); - strengthTable->atPut(Strength::WEAK_DEFAULT, 500); - strengthTable->atPut(Strength::ABSOLUTE_WEAKEST, 10000); - return strengthTable; - } - - - shared_ptr>> Strength::createStrengthConstants() { - shared_ptr>> strengthConstant = make_shared>>(); - _strengthTable->getKeys()->forEach([&](shared_ptr key) -> void { - shared_ptr keySym = dynamic_pointer_cast(key); - strengthConstant->atPut(keySym, make_shared(keySym)); - }); - - return strengthConstant; - } - - void Strength::initializeConstants() { - _strengthTable = createStrengthTable(); - _strengthConstant = createStrengthConstants(); - _absoluteWeakest = of(Strength::ABSOLUTE_WEAKEST); - _required = of(Strength::REQUIRED); - } - -} diff --git a/benchmarks/C++/src/deltablue/Strength.h b/benchmarks/C++/src/deltablue/Strength.h deleted file mode 100644 index 6719e881..00000000 --- a/benchmarks/C++/src/deltablue/Strength.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef STRENGTH -#define STRENGTH - -#include -#include -#include "../som/Dictionary.cpp" -#include "../som/IdentityDictionary.cpp" - -using namespace std; - -namespace deltablue { - class Strength : public enable_shared_from_this { - public: - class Sym : public CustomHash { - private: - int _hash; - - public: - Sym(int hash); - - int customHash() override; - }; - - static shared_ptr ABSOLUTE_STRONGEST; - static shared_ptr REQUIRED; - static shared_ptr STRONG_PREFERRED; - static shared_ptr PREFERRED; - static shared_ptr STRONG_DEFAULT; - static shared_ptr DEFAULT; - static shared_ptr WEAK_DEFAULT; - static shared_ptr ABSOLUTE_WEAKEST; - - private: - - int _arithmeticValue; - shared_ptr _symbolicValue; - - static shared_ptr> createStrengthTable(); - static shared_ptr>> createStrengthConstants(); - - public: - Strength(shared_ptr symbolicValue); - - bool sameAs(shared_ptr s) const; - bool stronger(shared_ptr s) const; - bool weaker(shared_ptr s) const; - shared_ptr strongest(shared_ptr s); - shared_ptr weakest(shared_ptr s); - int get_arithmeticValue() const; - static shared_ptr of(shared_ptr strength); - static shared_ptr absoluteWeakest(); - static shared_ptr required(); - static void initializeConstants(); - private: - - static shared_ptr _absoluteWeakest; - static shared_ptr _required; - - static shared_ptr> _strengthTable; - static shared_ptr>> _strengthConstant; - - }; - - - -} - -#endif //STRENGTHPLAN \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/UnaryConstraint.cpp b/benchmarks/C++/src/deltablue/UnaryConstraint.cpp deleted file mode 100644 index 0e42f2b8..00000000 --- a/benchmarks/C++/src/deltablue/UnaryConstraint.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include "UnaryConstraint.h" - -using namespace std; - -namespace deltablue { - UnaryConstraint::UnaryConstraint(shared_ptr v, shared_ptr strength, shared_ptr planner) - : AbstractConstraint(strength) { - _output = v; - _satisfied = false; - //addConstraint(planner); - } - - bool UnaryConstraint::isSatisfied() { - return _satisfied; - } - - // Add myself to the constraint graph. - void UnaryConstraint::addToGraph() { - _output->addConstraint(shared_from_this()); - _satisfied = false; - } - - // Remove myself from the constraint graph. - void UnaryConstraint::removeFromGraph() { - if (_output != nullptr) { - _output->removeConstraint(shared_from_this()); - } - _satisfied = false; - } - - Direction UnaryConstraint::chooseMethod(int mark) { - _satisfied = (_output->getMark() != mark) && _strength->stronger(_output->getWalkStrength()); - return NONE; - } - - void UnaryConstraint::inputsDo(function)> fn) { - // I have no input variables - } - - bool UnaryConstraint::inputsHasOne(function)> fn) { - return false; - } - - void UnaryConstraint::markUnsatisfied() { - _satisfied = false; - } - - shared_ptr UnaryConstraint::getOutput() { - return _output; - } - - void UnaryConstraint::recalculate() { - _output->setWalkStrength(_strength); - _output->setStay(!isInput()); - if (_output->getStay()) { - execute(); - } - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/UnaryConstraint.h b/benchmarks/C++/src/deltablue/UnaryConstraint.h deleted file mode 100644 index 2690de3d..00000000 --- a/benchmarks/C++/src/deltablue/UnaryConstraint.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef UNARYCONSTRAINT -#define UNARYCONSTRAINT - -#include -#include "AbstractConstraint.h" - -using namespace std; - -namespace deltablue { - class UnaryConstraint : public AbstractConstraint { - protected: - shared_ptr _output; // possible output variable - bool _satisfied; // true if I am currently satisfied - - public: - UnaryConstraint(shared_ptr v, shared_ptr strength, shared_ptr planner); - - bool isSatisfied() override; - void addToGraph() override; - void removeFromGraph() override; - Direction chooseMethod(int mark) override; - virtual void execute() = 0; - void inputsDo(function)> fn) override; - bool inputsHasOne(function)> fn) override; - void markUnsatisfied() override; - shared_ptr getOutput() override; - void recalculate() override; - - }; -} - -#endif //UNARYCONSTRAINT \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Variable.cpp b/benchmarks/C++/src/deltablue/Variable.cpp deleted file mode 100644 index 456b2def..00000000 --- a/benchmarks/C++/src/deltablue/Variable.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "AbstractConstraint.h" - -using namespace std; - -namespace deltablue { - - shared_ptr Variable::value(int aValue) { - shared_ptr v = make_shared(); - v->setValue(aValue); - return v; - } - - Variable::Variable() { - _value = 0; - _constraints = make_shared>>(2); - _determinedBy = nullptr; - _walkStrength = Strength::absoluteWeakest(); - _stay = true; - _mark = 0; - } - - void Variable::addConstraint(shared_ptr c) { - _constraints->append(c); - } - - shared_ptr>> Variable::getConstraints() { - return _constraints; - } - - shared_ptr Variable::getDeterminedBy() const { - return _determinedBy; - } - - void Variable::setDeterminedBy(shared_ptr c) { - _determinedBy = c; - } - - int Variable::getMark() const { - return _mark; - } - - void Variable::setMark(int markValue) { - _mark = markValue; - } - - void Variable::removeConstraint(shared_ptr c) { - _constraints->remove(c); - if (_determinedBy == c) { - _determinedBy = nullptr; - } - } - - bool Variable::getStay() const { - return _stay; - } - - void Variable::setStay(bool v) { - _stay = v; - } - - int Variable::getValue() const { - return _value; - } - - void Variable::setValue(int value) { - _value = value; - } - - shared_ptr Variable::getWalkStrength() { - return _walkStrength; - } - - void Variable::setWalkStrength(shared_ptr strength) { - _walkStrength = strength; - } - -} \ No newline at end of file diff --git a/benchmarks/C++/src/deltablue/Variable.h b/benchmarks/C++/src/deltablue/Variable.h deleted file mode 100644 index ca247b8c..00000000 --- a/benchmarks/C++/src/deltablue/Variable.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef VARIABLE -#define VARIABLE - -#include "Strength.h" -#include "../som/Vector.cpp" -#include - -using namespace std; - -namespace deltablue { - - class AbstractConstraint; - - class Variable { - private: - - int _value; - shared_ptr>> _constraints; - shared_ptr _determinedBy; - int _mark; - shared_ptr _walkStrength; - bool _stay; - - public: - Variable(); - - static shared_ptr value(int aValue); - void addConstraint(shared_ptr c); - shared_ptr>> getConstraints(); - shared_ptr getDeterminedBy() const; - void setDeterminedBy(shared_ptr c); - int getMark() const; - void setMark(int markValue); - void removeConstraint(shared_ptr c); - bool getStay() const; - void setStay(bool v); - int getValue() const; - void setValue(int value); - shared_ptr getWalkStrength(); - void setWalkStrength(shared_ptr strength); - }; -} - -#endif //VARIABLE \ No newline at end of file diff --git a/benchmarks/C++/src/run.h b/benchmarks/C++/src/run.h index 7074884d..a8132267 100644 --- a/benchmarks/C++/src/run.h +++ b/benchmarks/C++/src/run.h @@ -4,6 +4,7 @@ #include #include "bounce.h" +#include "deltablue.h" #include "mandelbrot.h" #include "permute.h" #include "queens.h" @@ -69,6 +70,9 @@ class Run { if (name == "Towers") { return []() -> Benchmark* { return new Towers(); }; } + if (name == "DeltaBlue") { + return []() -> Benchmark* { return new DeltaBlue(); }; + } std::cerr << "Benchmark not recognized: " << name << "\n"; exit(1); @@ -78,7 +82,7 @@ class Run { auto start_time = std::chrono::high_resolution_clock::now(); if (!bench->inner_benchmark_loop(inner_iterations)) { std::cout << "Benchmark failed with incorrect result\n"; - exit(1); // TODO: should this be an exception? + exit(1); } auto end_time = std::chrono::high_resolution_clock::now(); const int64_t run_time = diff --git a/benchmarks/C++/src/som/Dictionary.cpp b/benchmarks/C++/src/som/Dictionary.cpp deleted file mode 100644 index b05814b1..00000000 --- a/benchmarks/C++/src/som/Dictionary.cpp +++ /dev/null @@ -1,259 +0,0 @@ -#ifndef DICTIONARY -#define DICTIONARY - - -#include -#include "Vector.cpp" - -class CustomHash { - public: - CustomHash() = default; - virtual int customHash()=0; -}; - -template -class Dictionary { - - public: - class Entry { - public: - int _hash; - shared_ptr _key; - V _value; - std::shared_ptr _next; - - public: - Entry(int h, const shared_ptr& k, const V& v, std::shared_ptr n) - : _hash(h), _key(k), _value(v), _next(n) {} - - virtual bool match(int h, const shared_ptr& k) { - return _hash == h && _key == k; - } - - const shared_ptr& getKey() const { - return _key; - } - - int getHash() const { - return _hash; - } - }; - - static const int INITIAL_CAPACITY = 16; - - std::shared_ptr* _buckets; - int _size; - int _capacity; - - public: - Dictionary(int capacity = INITIAL_CAPACITY) : _size(0), _capacity(capacity) { - _buckets = new std::shared_ptr[capacity](); - } - - ~Dictionary() { - removeAll(); - delete[] _buckets; - } - - int getSize() const { - return _size; - } - - bool isEmpty() const { - return _size == 0; - } - - int hash(const shared_ptr& key) const { - if (key == nullptr) { - return 0; - } - int h = key->customHash(); - return h ^ (h >> 16); - } - - bool containsKey(const shared_ptr& key) const { - int h = hash(key); - std::shared_ptr e = getBucket(h); - - while (e != nullptr) { - if (e->match(h, key)) { - return true; - } - e = e->_next; - } - return false; - } - - V atPtr(const shared_ptr& key) const { - int h = hash(key); - std::shared_ptr e = getBucket(h); - - while (e != nullptr) { - if (e->match(h, key)) { - return e->_value; - } - e = e->_next; - } - return nullptr; - } - - - V at(const shared_ptr& key) const { - int h = this->hash(key); - std::shared_ptr e = getBucket(h); - - while (e != nullptr) { - if (e->match(h, key)) { - return e->_value; - } - e = e->_next; - } - // Return a default-constructed V if the key is not found - return V(); - } - - void atPut(const shared_ptr& key, const V& value) { - int h = hash(key); - int i = getBucketIdx(h); - - std::shared_ptr current = _buckets[i]; - - if (current == nullptr) { - _buckets[i] = newEntry(key, value, h); - _size += 1; - } else { - insertBucketEntry(key, value, h, current); - } - - if (_size > _capacity) { - resize(); - } - } - - void removeAll() { - for(int i = 0; i < _capacity; i++) { - _buckets[i] = nullptr; // Reset each element to a default value - } - _size = 0; - } - - shared_ptr>> getKeys() { - shared_ptr>> keys = make_shared>>(); - for (int i = 0; i < _capacity; i++) { - std::shared_ptr current = _buckets[i]; - while (current != nullptr) { - keys->append(current->_key); - current = current->_next; - } - } - return keys; - } - - shared_ptr> getValues() { - shared_ptr> values = make_shared>(_size); - - for (int i = 0; i < _capacity; i++) { - std::shared_ptr current = _buckets[i]; - while (current != nullptr) { - values->append(current->_value); - current = current->_next; - } - } - return values; - } - - virtual std::shared_ptr newEntry(shared_ptr key, V value, int hash) { - return make_shared(hash, key, value, nullptr); - } - - private: - int getBucketIdx(int hash) const { - return (_capacity - 1) & hash; - } - - std::shared_ptr getBucket(int hash) const { - return _buckets[getBucketIdx(hash)]; - } - - void insertBucketEntry(const shared_ptr& key, const V& value, int hash, std::shared_ptr head) { - std::shared_ptr current = head; - - while (true) { - if (current->match(hash, key)) { - current->_value = value; - return; - } - if (current->_next == nullptr) { - _size += 1; - current->_next = newEntry(key, value, hash); - return; - } - current = current->_next; - } - } - - void resize() { - std::shared_ptr* oldStorage = _buckets; - int oldCapacity = _capacity; - _capacity *= 2; - std::shared_ptr* newStorage = new shared_ptr[_capacity](); - _buckets = newStorage; - transferEntries(oldStorage, oldCapacity); - delete[] oldStorage; - } - - void transferEntries(std::shared_ptr* oldStorage, int oldCapacity) { - for (int i = 0; i < oldCapacity; i++) { - shared_ptr current = oldStorage[i]; - if (current != nullptr) { - oldStorage[i] = nullptr; - if (current->_next == nullptr) { - _buckets[current->_hash & (oldCapacity - 1)] = current; - } else { - splitBucket(i, current, oldCapacity); - } - } - } - } - - void splitBucket(int idx, std::shared_ptr head, int oldCapacity) { - std::shared_ptr loHead = nullptr; - std::shared_ptr loTail = nullptr; - std::shared_ptr hiHead = nullptr; - std::shared_ptr hiTail = nullptr; - - std::shared_ptr current = head; - - while (current != nullptr) { - if ((current->_hash & oldCapacity) == 0) { - if (loTail == nullptr) { - loHead = current; - } else { - loTail->_next = current; - } - loTail = current; - } else { - if (hiTail == nullptr) { - hiHead = current; - } else { - hiTail->_next = current; - } - hiTail = current; - } - current = current->_next; - } - - if (loTail != nullptr) { - loTail->_next = nullptr; - _buckets[idx] = loHead; - } - if (hiTail != nullptr) { - hiTail->_next = nullptr; - _buckets[idx + oldCapacity] = hiHead; - } - } - -}; - - -#endif //DICTIONARY \ No newline at end of file diff --git a/benchmarks/C++/src/som/Error.cpp b/benchmarks/C++/src/som/Error.cpp deleted file mode 100644 index c5d6621a..00000000 --- a/benchmarks/C++/src/som/Error.cpp +++ /dev/null @@ -1,27 +0,0 @@ - -#ifndef ERROR -#define ERROR - -#include - -using namespace std; - -class Error : virtual public exception { - private: - string _what; - - public: - Error(string const &what) { - _what = what; - } - - Error(const char *what) { - _what = string(what); - } - - const char *what() const throw() { - return (_what.c_str()); - } -}; - -#endif //ERROR \ No newline at end of file diff --git a/benchmarks/C++/src/som/IdentityDictionary.cpp b/benchmarks/C++/src/som/IdentityDictionary.cpp deleted file mode 100644 index cf433227..00000000 --- a/benchmarks/C++/src/som/IdentityDictionary.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef IDENTITYDICTIONARY -#define IDENTITYDICTIONARY - -#include "Dictionary.cpp" -#include - -template -class IdentityDictionary : public Dictionary { - public: - class IdEntry : public Dictionary::Entry { - public: - IdEntry(int hash, const shared_ptr& key, const V& value, std::shared_ptr::Entry> next) - : Dictionary::Entry(hash, key, value, next) {} - - bool match(int h, const shared_ptr& k) override { - return this->getHash() == h && this->getKey() == k; - } - }; - - public: - IdentityDictionary(const int size) : Dictionary(size) {} - IdentityDictionary() : Dictionary(Dictionary::INITIAL_CAPACITY) {} - - std::shared_ptr::Entry> newEntry(shared_ptr key, V value, int hash) override { - return make_shared(hash, key, value, nullptr); - } -}; - -#endif //IDENTITYDICTIONARY \ No newline at end of file diff --git a/benchmarks/C++/src/som/Vector.cpp b/benchmarks/C++/src/som/Vector.cpp deleted file mode 100644 index 920bd7a7..00000000 --- a/benchmarks/C++/src/som/Vector.cpp +++ /dev/null @@ -1,240 +0,0 @@ -#ifndef VECTOR -#define VECTOR - -#include -#include -#include -#include -#include -#include -using namespace std; - -template -class Vector { - private: - E* storage; - size_t _capacity; - size_t _firstIdx; - size_t _lastIdx; - - static void swap(E* storage2, int i, int j) { - throw std::logic_error("Function swap not yet implemented"); - } - - void defaultSort(int i, int j) { - throw std::logic_error("Function defaultSort not yet implemented"); - } - - void sort(int i, int j, std::function c) { - if (c == nullptr) { - defaultSort(i, j); - return; // Make sure to return if c is nullptr. - } - - int n = j + 1 - i; - if (n <= 1) { - return; - } - - E di = storage[i]; - E dj = storage[j]; - - if (c(di, dj) > 0) { - swap(storage, i, j); - E tt = di; - di = dj; - dj = tt; - } - - if (n > 2) { - int ij = (i + j) / 2; - E dij = storage[ij]; - - if (c(di, dij) <= 0) { - if (c(dij, dj) > 0) { - swap(storage, j, ij); - dij = dj; - } - } else { - swap(storage, i, ij); - dij = di; - } - - if (n > 3) { - int k = i; - int l = j - 1; - - while (true) { - while (k <= l && c(dij, storage[l]) <= 0) { - l -= 1; - } - - k += 1; - while (k <= l && c(storage[k], dij) <= 0) { - k += 1; - } - - if (k > l) { - break; - } - swap(storage, k, l); - } - - sort(i, l, c); - sort(k, j, c); - } - } - } - - - - public: - static shared_ptr> with(const E& elem) { - shared_ptr> v = make_shared>(1); - v->append(elem); - return v; - } - - explicit Vector(size_t size) : _capacity(size), _firstIdx(0), _lastIdx(0) { - storage = new E[_capacity]; - } - - Vector() : Vector(50) {} - - ~Vector() { - delete[] storage; - } - - E atPtr(size_t idx) const { - if (idx >= _lastIdx - _firstIdx) { - return nullptr; - } - return storage[_firstIdx + idx]; - } - - E at(size_t idx) const { - if (idx >= _lastIdx - _firstIdx) { - return E(); - } - return storage[_firstIdx + idx]; - } - - void atPut(size_t idx, const E& val) { - if (idx >= _lastIdx - _firstIdx) { - size_t newLength = _capacity; - while (newLength <= idx + _firstIdx) { - newLength *= 2; - } - E* newStorage = new E[newLength]; - for (size_t i = 0; i < _lastIdx; i++) { - newStorage[i] = storage[i]; - } - delete[] storage; - storage = newStorage; - _capacity = newLength; - } - storage[_firstIdx + idx] = val; - if (_lastIdx < idx + 1) { - _lastIdx = idx + 1; - } - } - - void append(const E& elem) { - if (_lastIdx >= _capacity) { - // Need to expand _capacity first - _capacity *= 2; - E* newStorage = new E[_capacity]; - for (size_t i = 0; i < _lastIdx; i++) { - newStorage[i] = storage[i]; - } - delete[] storage; - storage = newStorage; - } - - storage[_lastIdx] = elem; - _lastIdx++; - } - - - bool isEmpty() const { - return _lastIdx == _firstIdx; - } - - void forEach(const std::function& fn) const { - for (size_t i = _firstIdx; i < _lastIdx; i++) { - fn(storage[i]); - } - } - - bool hasSome(const std::function& fn) const { - for (size_t i = _firstIdx; i < _lastIdx; i++) { - if (fn(storage[i])) { - return true; - } - } - return false; - } - - E getOne(const std::function& fn) const { - for (size_t i = _firstIdx; i < _lastIdx; i++) { - const E& e = storage[i]; - if (fn(e)) { - return e; - } - } - return nullptr; // Return a default-constructed object if not found - } - - E first() const { - if (isEmpty()) { - return nullptr; // Return a default-constructed object for an empty vector - } - return storage[_firstIdx]; - } - - E removeFirst() { - if (isEmpty()) { - return nullptr; // Return a default-constructed object for an empty vector - } - _firstIdx++; - return storage[_firstIdx - 1]; - } - - bool remove(const E& obj) { - bool found = false; - size_t newLast = _firstIdx; - for (size_t i = _firstIdx; i < _lastIdx; i++) { - if (storage[i] == obj) { - found = true; - } else { - storage[newLast] = storage[i]; - newLast++; - } - } - _lastIdx = newLast; - return found; - } - - void removeAll() { - _firstIdx = 0; - _lastIdx = 0; - } - - size_t size() const { - return _lastIdx - _firstIdx; - } - - size_t getCapacity() const { - return _capacity; - } - - void sort(std::function c) { - if (size() > 0) { - sort(_firstIdx, _lastIdx - 1, c); - } - } - - -}; - -#endif //VECTOR diff --git a/benchmarks/C++/src/som/dictionary.h b/benchmarks/C++/src/som/dictionary.h new file mode 100644 index 00000000..0aeeba2f --- /dev/null +++ b/benchmarks/C++/src/som/dictionary.h @@ -0,0 +1,268 @@ +#pragma once + +#include +#include "vector.h" + +class CustomHash { + public: + CustomHash() = default; + virtual ~CustomHash() = default; + [[nodiscard]] virtual int32_t customHash() const = 0; +}; + +template +class IdentityDictionary; + +/** + * The Dictionary class does not manage the memory of keys and values. + * + * The memory of Entry objects is managed by ownership through the _buckets + * field. Thus, they are anchored in the _buckets, and only freed from there. + */ +template +class Dictionary { + friend class IdentityDictionary; + + private: + class Entry { + friend class IdentityDictionary; + friend class Dictionary; + + private: + int32_t _hash; + const CustomHash* const _key; + V _value; + Entry* _next; + + public: + Entry(int32_t h, const CustomHash* k, const V& v, Entry* n) + : _hash(h), _key(k), _value(v), _next(n) {} + virtual ~Entry() = default; + + virtual bool match(int32_t h, const CustomHash* const k) { + return _hash == h && _key == k; + } + + [[nodiscard]] const CustomHash* getKey() const { return _key; } + + [[nodiscard]] int32_t getHash() const { return _hash; } + }; + + static const int32_t INITIAL_CAPACITY = 16; + + Entry** _buckets; + int32_t _size{0}; + int32_t _capacity; + + public: + explicit Dictionary(int32_t capacity = INITIAL_CAPACITY) + : _buckets(new Entry* [capacity] {}), _capacity(capacity) {} + + virtual ~Dictionary() { + removeAll(); + delete[] _buckets; + } + + [[nodiscard]] int32_t getSize() const { return _size; } + + [[nodiscard]] bool isEmpty() const { return _size == 0; } + + [[nodiscard]] int32_t hash(const CustomHash* key) const { + if (key == nullptr) { + return 0; + } + const int32_t h = key->customHash(); + return h ^ (h >> 16); + } + + [[nodiscard]] bool containsKey(const CustomHash* key) const { + int32_t h = hash(key); + Entry* e = getBucket(h); + + while (e != nullptr) { + if (e->match(h, key)) { + return true; + } + e = e->_next; + } + return false; + } + + V atPtr(const CustomHash* key) const { + const int32_t h = hash(key); + Entry* e = getBucket(h); + + while (e != nullptr) { + if (e->match(h, key)) { + return e->_value; + } + e = e->_next; + } + return nullptr; + } + + V at(const CustomHash* key) const { + const int32_t h = this->hash(key); + Entry* e = getBucket(h); + + while (e != nullptr) { + if (e->match(h, key)) { + return e->_value; + } + e = e->_next; + } + // Return a default-constructed V if the key is not found + return V(); + } + + void atPut(const CustomHash* const key, const V& value) { + const int32_t h = hash(key); + const int32_t i = getBucketIdx(h); + + Entry* current = _buckets[i]; + + if (current == nullptr) { + _buckets[i] = newEntry(key, value, h); + _size += 1; + } else { + insertBucketEntry(key, value, h, current); + } + + if (_size > _capacity) { + resize(); + } + } + + void removeAll() { + for (int32_t i = 0; i < _capacity; i++) { + Entry* current = _buckets[i]; + while (current != nullptr) { + Entry* toBeDeleted = current; + current = current->_next; + delete toBeDeleted; + } + + _buckets[i] = nullptr; // Reset each element to a default value + } + _size = 0; + } + + [[nodiscard]] Vector* getKeys() { + auto* keys = new Vector(); + for (int32_t i = 0; i < _capacity; i++) { + Entry* current = _buckets[i]; + while (current != nullptr) { + keys->append(current->_key); + current = current->_next; + } + } + return keys; + } + + [[nodiscard]] Vector* getValues() { + auto* values = new Vector(_size); + + for (int32_t i = 0; i < _capacity; i++) { + Entry* current = _buckets[i]; + while (current != nullptr) { + values->append(current->_value); + current = current->_next; + } + } + return values; + } + + virtual Entry* newEntry(const CustomHash* key, V value, int32_t hash) { + return new Entry(hash, key, value, nullptr); + } + + private: + [[nodiscard]] int32_t getBucketIdx(int32_t hash) const { + return (_capacity - 1) & hash; + } + + [[nodiscard]] Entry* getBucket(int32_t hash) const { + return _buckets[getBucketIdx(hash)]; + } + + void insertBucketEntry(const CustomHash* key, + const V& value, + int32_t hash, + Entry* head) { + Entry* current = head; + + while (true) { + if (current->match(hash, key)) { + current->_value = value; + return; + } + if (current->_next == nullptr) { + _size += 1; + current->_next = newEntry(key, value, hash); + return; + } + current = current->_next; + } + } + + void resize() { + Entry** oldStorage = _buckets; + const int32_t oldCapacity = _capacity; + _capacity *= 2; + auto* newStorage = new Entry*[_capacity]; + _buckets = newStorage; + transferEntries(oldStorage, oldCapacity); + delete[] oldStorage; + } + + void transferEntries(Entry** oldStorage, int32_t oldCapacity) { + for (int32_t i = 0; i < oldCapacity; i++) { + Entry* current = oldStorage[i]; + if (current != nullptr) { + oldStorage[i] = nullptr; + if (current->_next == nullptr) { + _buckets[current->_hash & (oldCapacity - 1)] = current; + } else { + splitBucket(i, current, oldCapacity); + } + } + } + } + + void splitBucket(int32_t idx, Entry* head, int32_t oldCapacity) { + Entry* loHead = nullptr; + Entry* loTail = nullptr; + Entry* hiHead = nullptr; + Entry* hiTail = nullptr; + + Entry* current = head; + + while (current != nullptr) { + if ((current->_hash & oldCapacity) == 0) { + if (loTail == nullptr) { + loHead = current; + } else { + loTail->_next = current; + } + loTail = current; + } else { + if (hiTail == nullptr) { + hiHead = current; + } else { + hiTail->_next = current; + } + hiTail = current; + } + current = current->_next; + } + + if (loTail != nullptr) { + loTail->_next = nullptr; + _buckets[idx] = loHead; + } + if (hiTail != nullptr) { + hiTail->_next = nullptr; + _buckets[idx + oldCapacity] = hiHead; + } + } +}; diff --git a/benchmarks/C++/src/som/error.h b/benchmarks/C++/src/som/error.h new file mode 100644 index 00000000..52165bf0 --- /dev/null +++ b/benchmarks/C++/src/som/error.h @@ -0,0 +1,18 @@ + +#pragma once + +#include + +class Error : virtual public std::exception { + private: + std::string _what; + + public: + explicit Error(std::string const& what) : _what(what) {} // NOLINT + + explicit Error(const char* what) : _what(std::string(what)) {} + + [[nodiscard]] const char* what() const noexcept override { + return (_what.c_str()); + } +}; diff --git a/benchmarks/C++/src/som/identity_dictionary.h b/benchmarks/C++/src/som/identity_dictionary.h new file mode 100644 index 00000000..f484dd60 --- /dev/null +++ b/benchmarks/C++/src/som/identity_dictionary.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include "dictionary.h" + +template +class IdentityDictionary : public Dictionary { + private: + class IdEntry : public Dictionary::Entry { + public: + IdEntry(int hash, + const CustomHash* key, + const V& value, + typename Dictionary::Entry* next) + : Dictionary::Entry(hash, key, value, next) {} + ~IdEntry() override = default; + + bool match(int h, const CustomHash* k) override { + return this->getHash() == h && this->getKey() == k; + } + }; + + public: + explicit IdentityDictionary(const int size) : Dictionary(size) {} + IdentityDictionary() : Dictionary(Dictionary::INITIAL_CAPACITY) {} + + typename Dictionary::Entry* newEntry(const CustomHash* key, + V value, + int32_t hash) override { + return new IdEntry(hash, key, value, nullptr); + } +}; diff --git a/benchmarks/C++/src/som/random.h b/benchmarks/C++/src/som/random.h index 1c762698..86be6cdc 100644 --- a/benchmarks/C++/src/som/random.h +++ b/benchmarks/C++/src/som/random.h @@ -1,13 +1,12 @@ #pragma once class Random { -private: - int32_t seed {74755}; - -public: + private: + int32_t seed{74755}; + public: Random() = default; - + int32_t next() { seed = ((seed * 1309) + 13849) & 65535; return seed; diff --git a/benchmarks/C++/src/som/vector.h b/benchmarks/C++/src/som/vector.h new file mode 100644 index 00000000..c0ec2b07 --- /dev/null +++ b/benchmarks/C++/src/som/vector.h @@ -0,0 +1,225 @@ +#pragma once + +#include +#include +#include +#include +#include + +template +class Vector { + private: + E* storage; + size_t _capacity; + size_t _firstIdx{0}; + size_t _lastIdx{0}; + + void sort(size_t i, size_t j, std::function c) { + if (c == nullptr) { + defaultSort(i, j); + return; // Make sure to return if c is nullptr. + } + + const size_t n = j + 1 - i; + if (n <= 1) { + return; + } + + E di = storage[i]; + E dj = storage[j]; + + if (c(di, dj) > 0) { + swap(storage, i, j); + E tt = di; + di = dj; + dj = tt; + } + + if (n > 2) { + const size_t ij = (i + j) / 2; + E dij = storage[ij]; + + if (c(di, dij) <= 0) { + if (c(dij, dj) > 0) { + swap(storage, j, ij); + dij = dj; + } + } else { + swap(storage, i, ij); + dij = di; + } + + if (n > 3) { + size_t k = i; + size_t l = j - 1; + + while (true) { + while (k <= l && c(dij, storage[l]) <= 0) { + l -= 1; + } + + k += 1; + while (k <= l && c(storage[k], dij) <= 0) { + k += 1; + } + + if (k > l) { + break; + } + swap(storage, k, l); + } + + sort(i, l, c); + sort(k, j, c); + } + } + } + + public: + static Vector* with(const E& elem) { + auto v = new Vector(1); + v->append(elem); + return v; + } + + explicit Vector(size_t size) : storage(new E[size]), _capacity(size) {} + + Vector() : Vector(50) {} // NOLINT + + ~Vector() { delete[] storage; } + + [[nodiscard]] E atPtr(size_t idx) const { + if (idx >= _lastIdx - _firstIdx) { + return nullptr; + } + return storage[_firstIdx + idx]; + } + + [[nodiscard]] E at(size_t idx) const { + if (idx >= _lastIdx - _firstIdx) { + return E(); + } + return storage[_firstIdx + idx]; + } + + void atPut(size_t idx, const E& val) { + if (idx >= _lastIdx - _firstIdx) { + size_t newLength = _capacity; + while (newLength <= idx + _firstIdx) { + newLength *= 2; + } + E* newStorage = new E[newLength]; + for (size_t i = 0; i < _lastIdx; i++) { + newStorage[i] = storage[i]; + } + delete[] storage; + storage = newStorage; + _capacity = newLength; + } + storage[_firstIdx + idx] = val; + if (_lastIdx < idx + 1) { + _lastIdx = idx + 1; + } + } + + void append(const E& elem) { + if (_lastIdx >= _capacity) { + // Need to expand _capacity first + _capacity *= 2; + E* newStorage = new E[_capacity]; + for (size_t i = 0; i < _lastIdx; i++) { + newStorage[i] = storage[i]; + } + delete[] storage; + storage = newStorage; + } + + storage[_lastIdx] = elem; + _lastIdx++; + } + + [[nodiscard]] bool isEmpty() const { return _lastIdx == _firstIdx; } + + void forEach(const std::function& fn) const { + for (size_t i = _firstIdx; i < _lastIdx; i++) { + fn(storage[i]); + } + } + + bool hasSome(const std::function& fn) const { + for (size_t i = _firstIdx; i < _lastIdx; i++) { + if (fn(storage[i])) { + return true; + } + } + return false; + } + + E getOne(const std::function& fn) const { + for (size_t i = _firstIdx; i < _lastIdx; i++) { + const E& e = storage[i]; + if (fn(e)) { + return e; + } + } + return nullptr; // Return a default-constructed object if not found + } + + [[nodiscard]] E first() const { + if (isEmpty()) { + return nullptr; // Return a default-constructed object for an empty + // vector + } + return storage[_firstIdx]; + } + + E removeFirst() { + if (isEmpty()) { + return nullptr; // Return a default-constructed object for an empty + // vector + } + _firstIdx++; + return storage[_firstIdx - 1]; + } + + bool remove(const E& obj) { + bool found = false; + size_t newLast = _firstIdx; + for (size_t i = _firstIdx; i < _lastIdx; i++) { + if (storage[i] == obj) { + found = true; + } else { + storage[newLast] = storage[i]; + newLast++; + } + } + _lastIdx = newLast; + return found; + } + + void removeAll() { + _firstIdx = 0; + _lastIdx = 0; + } + + [[nodiscard]] size_t size() const { return _lastIdx - _firstIdx; } + + [[nodiscard]] size_t getCapacity() const { return _capacity; } + + void sort(std::function c) { + if (size() > 0) { + sort(_firstIdx, _lastIdx - 1, c); + } + } + + private: + static void swap(E*, size_t, size_t) { + std::cerr << "swap not implemented" << std::endl; + exit(1); + } + + void defaultSort(size_t, size_t) { + std::cerr << "defaultSort not implemented" << std::endl; + exit(1); + } +}; diff --git a/benchmarks/C++/src/storage.h b/benchmarks/C++/src/storage.h index 038885c0..d239f484 100644 --- a/benchmarks/C++/src/storage.h +++ b/benchmarks/C++/src/storage.h @@ -26,7 +26,7 @@ class Storage : public Benchmark { count = 0; ArrayTree* result = build_tree_depth(7, random); delete[] result; - + return reinterpret_cast(static_cast(count)); } @@ -41,7 +41,7 @@ class Storage : public Benchmark { return new ArrayTree[random.next() % 10 + 1]; } - ArrayTree* arr = new ArrayTree[4]; + auto* arr = new ArrayTree[4]; for (size_t i = 0; i < 4; i++) { arr[i].children = build_tree_depth(depth - 1, random); } From a8429f556d7253315f7cc61332a7395b8e567b4d Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 5 Jan 2024 12:15:32 +0000 Subject: [PATCH 04/40] [C++] Added a basic object tracker to be able to release memory of arbitrary graphs - explicitly free the key vector from getKeys() - explicitly release the DeltaBlue constants Signed-off-by: Stefan Marr --- benchmarks/C++/build.sh | 4 +++- benchmarks/C++/src/deltablue.cpp | 23 +++++++++++++++----- benchmarks/C++/src/deltablue.h | 14 +++++++----- benchmarks/C++/src/memory/object_tracker.cpp | 10 +++++++++ benchmarks/C++/src/memory/object_tracker.h | 21 ++++++++++++++++++ benchmarks/C++/src/som/dictionary.h | 10 +++++++++ 6 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 benchmarks/C++/src/memory/object_tracker.cpp create mode 100644 benchmarks/C++/src/memory/object_tracker.h diff --git a/benchmarks/C++/build.sh b/benchmarks/C++/build.sh index e39eceab..bd75ef3f 100755 --- a/benchmarks/C++/build.sh +++ b/benchmarks/C++/build.sh @@ -32,4 +32,6 @@ else OPT='-O3' fi -clang++-mp-16 -Wall -Wextra $SANATIZE $OPT -ffp-contract=off -std=c++17 src/harness.cpp src/deltablue.cpp -o harness +SRC='src/harness.cpp src/deltablue.cpp src/memory/object_tracker.cpp' + +clang++-mp-16 -Wall -Wextra $SANATIZE $OPT -ffp-contract=off -std=c++17 $SRC -o harness diff --git a/benchmarks/C++/src/deltablue.cpp b/benchmarks/C++/src/deltablue.cpp index b94c120a..198ba8b1 100644 --- a/benchmarks/C++/src/deltablue.cpp +++ b/benchmarks/C++/src/deltablue.cpp @@ -38,11 +38,12 @@ IdentityDictionary* Strength::createStrengthTable() { IdentityDictionary* Strength::createStrengthConstants() { auto* strengthConstant = new IdentityDictionary(); - _strengthTable->getKeys()->forEach( - [&strengthConstant](const CustomHash* const key) -> void { - const Sym* keySym = dynamic_cast(key); - strengthConstant->atPut(keySym, new Strength(keySym)); - }); + auto* keys = _strengthTable->getKeys(); + keys->forEach([&strengthConstant](const CustomHash* const key) -> void { + const Sym* keySym = dynamic_cast(key); + strengthConstant->atPut(keySym, new Strength(keySym)); + }); + delete keys; return strengthConstant; } @@ -54,6 +55,18 @@ void Strength::initializeConstants() { _required = of(&Strength::REQUIRED); } +void Strength::releaseStrengthConstants() { + _strengthConstant->destroyValues(); + delete _strengthConstant; +} + +void Strength::releaseConstants() { + delete _strengthTable; + Strength::releaseStrengthConstants(); + _absoluteWeakest = nullptr; + _required = nullptr; +} + void AbstractConstraint::addConstraint(Planner* planner) { addToGraph(); planner->incrementalAdd(this); diff --git a/benchmarks/C++/src/deltablue.h b/benchmarks/C++/src/deltablue.h index bc42260d..4a0cef2a 100644 --- a/benchmarks/C++/src/deltablue.h +++ b/benchmarks/C++/src/deltablue.h @@ -1,6 +1,7 @@ #pragma once #include "benchmark.h" +#include "memory/object_tracker.h" #include "som/error.h" #include "som/identity_dictionary.h" #include "som/vector.h" @@ -35,6 +36,7 @@ class Strength { static IdentityDictionary* createStrengthTable(); static IdentityDictionary* createStrengthConstants(); + static void releaseStrengthConstants(); public: explicit Strength(const Sym* const symbolicValue) @@ -69,6 +71,7 @@ class Strength { static const Strength* absoluteWeakest(); static const Strength* required(); static void initializeConstants(); + static void releaseConstants(); private: static const Strength* _absoluteWeakest; @@ -81,7 +84,7 @@ class Strength { class Planner; class Variable; -class AbstractConstraint { +class AbstractConstraint : public TrackedObject { protected: const Strength* const _strength; Planner* const _planer{nullptr}; @@ -90,8 +93,6 @@ class AbstractConstraint { explicit AbstractConstraint(const Sym* strength) : _strength(Strength::of(strength)) {} - virtual ~AbstractConstraint() = default; - [[nodiscard]] const Strength* getStrength() { return _strength; } virtual bool isInput() { return false; } @@ -112,7 +113,7 @@ class AbstractConstraint { virtual void recalculate() = 0; }; -class Variable { +class Variable : public TrackedObject { private: int32_t _value{0}; Vector* _constraints; @@ -126,7 +127,7 @@ class Variable { : _constraints(new Vector(2)), _walkStrength(Strength::absoluteWeakest()) {} - ~Variable() { delete _constraints; } + ~Variable() override { delete _constraints; } static Variable* value(int32_t aValue) { auto* v = new Variable(); @@ -652,6 +653,7 @@ class Planner { editC->destroyConstraint(&planner); delete plan; delete[] vars; + ObjectTracker::releaseAll(); } static void projectionTest(int32_t n) { @@ -695,6 +697,8 @@ class Planner { throw Error("Projection test 4 failed!"); } } + ObjectTracker::releaseAll(); + Strength::releaseConstants(); } }; diff --git a/benchmarks/C++/src/memory/object_tracker.cpp b/benchmarks/C++/src/memory/object_tracker.cpp new file mode 100644 index 00000000..47b126a3 --- /dev/null +++ b/benchmarks/C++/src/memory/object_tracker.cpp @@ -0,0 +1,10 @@ +#include "object_tracker.h" + +std::vector ObjectTracker::trackedObjects{}; + +void ObjectTracker::releaseAll() { + for (auto* obj : trackedObjects) { + delete obj; + } + trackedObjects.clear(); +} diff --git a/benchmarks/C++/src/memory/object_tracker.h b/benchmarks/C++/src/memory/object_tracker.h new file mode 100644 index 00000000..9355e075 --- /dev/null +++ b/benchmarks/C++/src/memory/object_tracker.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +class TrackedObject; + +class ObjectTracker { + private: + static std::vector trackedObjects; + + public: + static void track(TrackedObject* obj) { trackedObjects.push_back(obj); } + + static void releaseAll(); +}; + +class TrackedObject { + public: + TrackedObject() { ObjectTracker::track(this); } + virtual ~TrackedObject() = default; +}; diff --git a/benchmarks/C++/src/som/dictionary.h b/benchmarks/C++/src/som/dictionary.h index 0aeeba2f..a49e20a4 100644 --- a/benchmarks/C++/src/som/dictionary.h +++ b/benchmarks/C++/src/som/dictionary.h @@ -172,6 +172,16 @@ class Dictionary { return values; } + void destroyValues() { + for (int32_t i = 0; i < _capacity; i++) { + Entry* current = _buckets[i]; + while (current != nullptr) { + delete current->_value; + current = current->_next; + } + } + } + virtual Entry* newEntry(const CustomHash* key, V value, int32_t hash) { return new Entry(hash, key, value, nullptr); } From 36dc5494a133ab115bb3915c36c75f246200beb4 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 5 Jan 2024 14:26:29 +0000 Subject: [PATCH 05/40] [C++] Expand build.sh, and document how to use LeakSanatizer - add file to suppress macOS static leaks - add more santizer options to build.sh - add a bit logic to select clang version - update clang version - add pedantic building option Signed-off-by: Stefan Marr --- benchmarks/C++/.clang-leak.txt | 2 ++ benchmarks/C++/build.sh | 63 +++++++++++++++++++++++++++------- 2 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 benchmarks/C++/.clang-leak.txt diff --git a/benchmarks/C++/.clang-leak.txt b/benchmarks/C++/.clang-leak.txt new file mode 100644 index 00000000..aa89e219 --- /dev/null +++ b/benchmarks/C++/.clang-leak.txt @@ -0,0 +1,2 @@ +leak:_fetchInitializingClassList +leak:libobjc \ No newline at end of file diff --git a/benchmarks/C++/build.sh b/benchmarks/C++/build.sh index bd75ef3f..de4599a0 100755 --- a/benchmarks/C++/build.sh +++ b/benchmarks/C++/build.sh @@ -1,37 +1,76 @@ #!/bin/bash + +# start by trying to find a suitable clang +CMD_VERSION='-mp-17' + +if ! [ -x "$(command -v clang++$CMD_VERSION)" ]; then + CMD_VERSION='-17' +fi + +CMD="clang++$CMD_VERSION" + if [ "$1" = "format" ] then CMD=clang-format - type -P "$CMD" || CMD=clang-format-mp-16 - $CMD -i --style=file src/*.cpp src/*.h src/**/*.cpp src/**/*.h - exit 0 + type -P "$CMD" || CMD=clang-format$CMD_VERSION + exec $CMD -i --style=file src/*.cpp src/*.h src/**/*.cpp src/**/*.h fi if [ "$1" = "check-format" ] then CMD=clang-format - type -P "$CMD" || CMD=clang-format-mp-16 - $CMD --style=file --dry-run --Werror src/*.cpp src/*.h src/**/*.cpp src/**/*.h - exit 0 + type -P "$CMD" || CMD=clang-format$CMD_VERSION + exec $CMD --style=file --dry-run --Werror src/*.cpp src/*.h src/**/*.cpp src/**/*.h fi if [ "$1" = "lint" ] then CMD=clang-tidy - type -P "$CMD" || CMD=clang-tidy-mp-16 - $CMD --config-file=.clang-tidy -header-filter=.* src/*.cpp - exit 0 + type -P "$CMD" || CMD=clang-tidy$CMD_VERSION + exec $CMD --config-file=.clang-tidy -header-filter=.* src/*.cpp fi -if [ "$1" = "sanitize" ] +if [ "$1" = "leak-san" ] then + echo Bulding with Leak Sanitizer enabled + # then run with LSAN_OPTIONS=suppressions=.clang-leak.txt ./harness Towers 20 1000 SANATIZE='-g -fsanitize=leak' OPT='-Og' +elif [ "$1" = "address-san" ] +then + echo Bulding with Address Sanitizer enabled + SANATIZE='-g -fsanitize=address' + OPT='-Og' +elif [ "$1" = "memory-san" ] +then + echo Bulding with Memory Sanitizer enabled + SANATIZE='-g -fsanitize=memory' + OPT='-Og' +elif [ "$1" = "undefined-san" ] +then + echo Bulding with Undefined Behavior Sanitizer enabled + SANATIZE='-g -fsanitize=undefined' + OPT='-Og' +elif [ "$1" = "pedantic" ] +then + DISABLED_WARNINGS='-Wno-poison-system-directories -Wno-c++98-compat + -Wno-shadow + -Wno-shadow-field-in-constructor -Wno-unused-private-field + -Wno-padded + -Wno-global-constructors + -Wno-exit-time-destructors + -Wno-float-equal + -Wno-sign-conversion + -Wno-unsafe-buffer-usage -Wno-weak-vtables' + SANATIZE="-Weverything -pedantic -Wall -Wextra $DISABLED_WARNINGS" + OPT='-O3' + echo Bulding with pedantic warnings and $OPT optimizations else + + echo Bulding with $OPT optimizations SANATIZE='' - OPT='-O3' fi SRC='src/harness.cpp src/deltablue.cpp src/memory/object_tracker.cpp' -clang++-mp-16 -Wall -Wextra $SANATIZE $OPT -ffp-contract=off -std=c++17 $SRC -o harness +exec $CMD -Wall -Wextra -Wno-unused-private-field $SANATIZE $OPT -ffp-contract=off -std=c++17 $SRC -o harness From 864e11df508255d0b09967bd2265731bcf7d1fb6 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 5 Jan 2024 15:00:12 +0000 Subject: [PATCH 06/40] [C++] Added C++ Guidelines Signed-off-by: Stefan Marr --- docs/guidelines.md | 107 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/docs/guidelines.md b/docs/guidelines.md index fcdfd67b..70606b73 100644 --- a/docs/guidelines.md +++ b/docs/guidelines.md @@ -143,6 +143,113 @@ languages. ### Python - Use plain fields instead of getter/setter when they would be trivial + + +### C++ + +With C++, we add support for the first language that does not have garbage +collection, which comes with a new dimension of issues to be considered. + +Explicit Memory Management Rules: + + - benchmarks have to run without memory leaks + + - stack allocation can be used where natural and where it does not change the + nature of the benchmark, for instance when an object/array is used only in + the dynamic scope of a function + + - existing data structures should be used where possible to manage + dynamically-created objects, for instance, iterate over an already existing + list of objects at the end of the benchmark or a method to free them + + - changes to code structure and APIs should be as minimal as possible, + for instance, if a method returns an allocated object, leave it as such, + and let the caller manage the memory + + - if the useful lifetime of object fields is restricted to a method, + the allocations referenced by these fields should be freed before + the end of a method, but the field should remain a field. + + - for arbitrary object graphs, as in DeltaBlue, memory/object_tracker.h can + be used to free the objects when not needed. + The use of shared_ptr may also be appropriate, but did not work for DeltaBlue. + +Memory Management Strategies Per Benchmarks: + + - **CD** use value objects for most data. Since it's a tree, the red/black tree + is trivially managed by deleting the nodes from the root. Vectors are managed + explicitly for the voxel map. Don't miss the empty vectors that are not + passed on as result though. + + - **DeltaBlue** uses `object_tracker`, since there are cyclic dependencies, + but we can free the full setup once it's not needed. + A mix of `shared_ptr` and `weak_ptr` would probably also work. + + - **Havlak** manages memory explicitly by assigning ownership to specific + classes. Specifically, the ControlFlowGraph owns the basic blocks and + block edges, the LoopStructureGraph owns the loops, the HavlakLoopFinder + owns its data including UnionFindNodes. Thus, the destructors can free + the corresponding memory. + + - **Json** relies on JSON documents being trees, and uses the + tree to free objects. The major tradeoff here is that we need to allocate + `true`, `false`, and `null` literal objects to have a uniform memory representation. + Though, otherwise, we do not require any management overhead. + + - **Richards** uses `object_tracker` for simplicity. + It could use `shared_ptr` and accounting for cyclic references that would + work, too. A naive using of the task list did not seem to work, + but I might have missed something. + + - **Bounce** allocates everything statically, i.e., on the stack. + + - **List** trivially uses the list structure for freeing the list. + + - **Mandelbrot** does not allocate any data structures. + + - **NBody** allocates everything statically, i.e., on the stack. + + - **Permute** allocates an array dynamically, and frees it directly. + Since the benchmark holds the reference in a field, and allocates on + each iteration, the new/delete dance is needed to comply + + - **Queens** allocates its arrays dynamically, and frees them directly, + same as Permute. + + - **Sieve** allocates everything statically, i.e., on the stack. + + - **Storage** allocates its tree dynamically, and frees it from the root. + + - **Towers** allocates the disks dynamically, which form a linked list, + that is used to free them once not needed anymore. + +General C++-isms: + + - the benchmarks, where possible, can be in headers only to match the code + structure of other languages + + - we use clang-tidy and clang-format + + - use std::array for fixed-sized arrays + + - use `const` where it is appropriate, but it won't really work with containers + and can be problematic for value classes + + - use `auto` and `auto*` to make code more concise as recommended by linter, + for instance for allocations + + - use annotations like [[nodiscard]] where indicated by the linter + + - use modern C++-isms, for instance range loops and .at instead of [] on std::array + + - use initializer syntax for default values and member initializers lists when depending on constructor parameter + + - prefer `int32_t`, `size_t` and similar to be more explicit about semantics + and size of value, plain `int`/`long` shouldn't be used + + - avoid changing signatures for the sake of the compiler. It should do an + appropriate return-value optimization itself. + ## Repository Structure From c166573f0da4a277cab2b2fdef6c71023653a945 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 5 Jan 2024 15:32:13 +0000 Subject: [PATCH 07/40] [C++] Added NBody port by Hugo Jenningros Signed-off-by: Stefan Marr --- benchmarks/C++/src/NBody.cpp | 38 ++++++++++ benchmarks/C++/src/NBody.h | 22 ++++++ benchmarks/C++/src/nbody/Body.cpp | 87 ++++++++++++++++++++++ benchmarks/C++/src/nbody/Body.h | 55 ++++++++++++++ benchmarks/C++/src/nbody/NBodySystem.cpp | 91 ++++++++++++++++++++++++ benchmarks/C++/src/nbody/NBodySystem.h | 24 +++++++ 6 files changed, 317 insertions(+) create mode 100644 benchmarks/C++/src/NBody.cpp create mode 100644 benchmarks/C++/src/NBody.h create mode 100644 benchmarks/C++/src/nbody/Body.cpp create mode 100644 benchmarks/C++/src/nbody/Body.h create mode 100644 benchmarks/C++/src/nbody/NBodySystem.cpp create mode 100644 benchmarks/C++/src/nbody/NBodySystem.h diff --git a/benchmarks/C++/src/NBody.cpp b/benchmarks/C++/src/NBody.cpp new file mode 100644 index 00000000..f4f7cdc1 --- /dev/null +++ b/benchmarks/C++/src/NBody.cpp @@ -0,0 +1,38 @@ +#include "NBody.h" + +using namespace std; + +namespace nbody { + + bool NBody::verifyResult(double result, int innerIterations) { + if (innerIterations == 250000) { + return result == -0.1690859889909308; + } + if (innerIterations == 1) { + return result == -0.16907495402506745; + } + + cout << "No verification result for " << innerIterations << " found" << endl; + cout << "Result is: " << result << endl; + return false; + } + + + bool NBody::innerBenchmarkLoop(int innerIterations) { + shared_ptr system = make_shared(); + for (int i = 0; i < innerIterations; i++) { + system->advance(0.01); + } + + return verifyResult(system->energy(), innerIterations); + } + + any NBody::benchmark() { + throw Error("Should never be reached"); + } + + bool NBody::verifyResult(any result) { + (void)result; + throw Error("Should never be reached"); + } +} diff --git a/benchmarks/C++/src/NBody.h b/benchmarks/C++/src/NBody.h new file mode 100644 index 00000000..bff5babc --- /dev/null +++ b/benchmarks/C++/src/NBody.h @@ -0,0 +1,22 @@ +#ifndef NBODY +#define NBODY + +#include "Benchmark.h" +#include "nbody/NBodySystem.h" +#include "som/Error.cpp" + +using namespace std; + +namespace nbody { + class NBody : public Benchmark { + private: + bool verifyResult(double result, int innerIterations); + + public: + bool innerBenchmarkLoop(int innerIterations) override; + any benchmark() override; + bool verifyResult(any result) override; + }; +} + +#endif //NBODY \ No newline at end of file diff --git a/benchmarks/C++/src/nbody/Body.cpp b/benchmarks/C++/src/nbody/Body.cpp new file mode 100644 index 00000000..391f6eca --- /dev/null +++ b/benchmarks/C++/src/nbody/Body.cpp @@ -0,0 +1,87 @@ +#include "Body.h" + +namespace nbody { + + double Body::getX() { return _x; } + double Body::getY() { return _y; } + double Body::getZ() { return _z; } + + double Body::getVX() { return _vx; } + double Body::getVY() { return _vy; } + double Body::getVZ() { return _vz; } + + double Body::getMass() { return _mass; } + + void Body::setX(double x) { _x = x; } + void Body::setY(double y) { _y = y; } + void Body::setZ(double z) { _z = z; } + + void Body::setVX(double vx) { _vx = vx; } + void Body::setVY(double vy) { _vy = vy; } + void Body::setVZ(double vz) { _vz = vz; } + + void Body::offsetMomentum(double px, double py, double pz) { + _vx = 0.0 - (px / SOLAR_MASS); + _vy = 0.0 - (py / SOLAR_MASS); + _vz = 0.0 - (pz / SOLAR_MASS); + } + + Body::Body(double x, double y, double z, + double vx, double vy, double vz, double mass) { + _x = x; + _y = y; + _z = z; + _vx = vx * DAYS_PER_YER; + _vy = vy * DAYS_PER_YER; + _vz = vz * DAYS_PER_YER; + _mass = mass * SOLAR_MASS; + } + + shared_ptr Body::jupiter() { + return make_shared( + 4.84143144246472090e+00, + -1.16032004402742839e+00, + -1.03622044471123109e-01, + 1.66007664274403694e-03, + 7.69901118419740425e-03, + -6.90460016972063023e-05, + 9.54791938424326609e-04); + } + + shared_ptr Body::saturn() { + return make_shared( + 8.34336671824457987e+00, + 4.12479856412430479e+00, + -4.03523417114321381e-01, + -2.76742510726862411e-03, + 4.99852801234917238e-03, + 2.30417297573763929e-05, + 2.85885980666130812e-04); + } + + shared_ptr Body::uranus() { + return make_shared( + 1.28943695621391310e+01, + -1.51111514016986312e+01, + -2.23307578892655734e-01, + 2.96460137564761618e-03, + 2.37847173959480950e-03, + -2.96589568540237556e-05, + 4.36624404335156298e-05); + } + + shared_ptr Body::neptune() { + return make_shared( + 1.53796971148509165e+01, + -2.59193146099879641e+01, + 1.79258772950371181e-01, + 2.68067772490389322e-03, + 1.62824170038242295e-03, + -9.51592254519715870e-05, + 5.15138902046611451e-05); + } + + shared_ptr Body::sun() { + return make_shared(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); + } +} diff --git a/benchmarks/C++/src/nbody/Body.h b/benchmarks/C++/src/nbody/Body.h new file mode 100644 index 00000000..3b5d0c66 --- /dev/null +++ b/benchmarks/C++/src/nbody/Body.h @@ -0,0 +1,55 @@ +#ifndef BODY +#define BODY + +#include + +using namespace std; + +namespace nbody { + class Body { + private: + constexpr static double PI = 3.141592653589793; + constexpr static double SOLAR_MASS = 4 * PI * PI; + constexpr static double DAYS_PER_YER = 365.24; + + double _x; + double _y; + double _z; + double _vx; + double _vy; + double _vz; + double _mass; + + public: + + double getX(); + double getY(); + double getZ(); + + double getVX(); + double getVY(); + double getVZ(); + + double getMass(); + + void setX(double x); + void setY(double y); + void setZ(double z); + + void setVX(double vx); + void setVY(double vy); + void setVZ(double vz); + + void offsetMomentum(double px, double py, double pz); + Body(double x, double y, double z, + double vx, double vy, double vz, double mass); + + static shared_ptr jupiter(); + static shared_ptr saturn(); + static shared_ptr uranus(); + static shared_ptr neptune(); + static shared_ptr sun(); + }; +} + +#endif //BODY \ No newline at end of file diff --git a/benchmarks/C++/src/nbody/NBodySystem.cpp b/benchmarks/C++/src/nbody/NBodySystem.cpp new file mode 100644 index 00000000..11e61a1a --- /dev/null +++ b/benchmarks/C++/src/nbody/NBodySystem.cpp @@ -0,0 +1,91 @@ +#include "NBodySystem.h" + +using namespace std; + +namespace nbody { + NBodySystem::NBodySystem() { + _bodiesSize = 5; + _bodies = createBodies(); + } + + shared_ptr* NBodySystem::createBodies() { + shared_ptr* bodies = new shared_ptr[5]; + bodies[0] = Body::sun(); + bodies[1] = Body::jupiter(); + bodies[2] = Body::saturn(); + bodies[3] = Body::uranus(); + bodies[4] = Body::neptune(); + + double px = 0.0; + double py = 0.0; + double pz = 0.0; + + for (int i = 0; i < _bodiesSize; ++i) { + px += bodies[i]->getVX() * bodies[i]->getMass(); + py += bodies[i]->getVY() * bodies[i]->getMass(); + pz += bodies[i]->getVZ() * bodies[i]->getMass(); + } + + bodies[0]->offsetMomentum(px, py, pz); + + return bodies; + } + + void NBodySystem::advance(double dt) { + for (int i = 0; i < _bodiesSize; ++i) { + shared_ptr iBody = _bodies[i]; + + for (int j = i + 1; j < _bodiesSize; ++j) { + shared_ptr jBody = _bodies[j]; + double dx = iBody->getX() - jBody->getX(); + double dy = iBody->getY() - jBody->getY(); + double dz = iBody->getZ() - jBody->getZ(); + + double dSquared = dx * dx + dy * dy + dz * dz; + double distance = sqrt(dSquared); + double mag = dt / (dSquared * distance); + + iBody->setVX(iBody->getVX() - (dx * jBody->getMass() * mag)); + iBody->setVY(iBody->getVY() - (dy * jBody->getMass() * mag)); + iBody->setVZ(iBody->getVZ() - (dz * jBody->getMass() * mag)); + + jBody->setVX(jBody->getVX() + (dx * iBody->getMass() * mag)); + jBody->setVY(jBody->getVY() + (dy * iBody->getMass() * mag)); + jBody->setVZ(jBody->getVZ() + (dz * iBody->getMass() * mag)); + } + } + + for (int i = 0; i < _bodiesSize; ++i) { + _bodies[i]->setX(_bodies[i]->getX() + dt * _bodies[i]->getVX()); + _bodies[i]->setY(_bodies[i]->getY() + dt * _bodies[i]->getVY()); + _bodies[i]->setZ(_bodies[i]->getZ() + dt * _bodies[i]->getVZ()); + } + } + + double NBodySystem::energy() { + double e = 0.0; + + for (int i = 0; i < _bodiesSize; ++i) { + shared_ptr iBody = _bodies[i]; + e += 0.5 * iBody->getMass() + * (iBody->getVX() * iBody->getVX() + + iBody->getVY() * iBody->getVY() + + iBody->getVZ() * iBody->getVZ()); + + for (int j = i + 1; j < _bodiesSize; ++j) { + shared_ptr jBody = _bodies[j]; + double dx = iBody->getX() - jBody->getX(); + double dy = iBody->getY() - jBody->getY(); + double dz = iBody->getZ() - jBody->getZ(); + + double distance = sqrt(dx * dx + dy * dy + dz * dz); + e -= (iBody->getMass() * jBody->getMass()) / distance; + } + } + delete[] _bodies; + return e; + } + +} + + \ No newline at end of file diff --git a/benchmarks/C++/src/nbody/NBodySystem.h b/benchmarks/C++/src/nbody/NBodySystem.h new file mode 100644 index 00000000..119c694a --- /dev/null +++ b/benchmarks/C++/src/nbody/NBodySystem.h @@ -0,0 +1,24 @@ +#ifndef NBODYSYSTEM +#define NBODYSYSTEM + +#include "Body.h" +#include + +using namespace std; + +namespace nbody { + class NBodySystem { + private: + shared_ptr* _bodies; + int _bodiesSize; + + public: + NBodySystem(); + + shared_ptr* createBodies(); + void advance(double dt); + double energy(); + }; +} + +#endif //NBODYSYSTEM \ No newline at end of file From bd5d3cc76ce6646d13ad4d604ed0beae54926bab Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 5 Jan 2024 16:26:18 +0000 Subject: [PATCH 08/40] [C++] Modernize NBody MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - don’t need memory management, since we can rely entierly on statically known information and stack allocation Signed-off-by: Stefan Marr --- benchmarks/C++/src/NBody.cpp | 38 ----- benchmarks/C++/src/NBody.h | 22 --- benchmarks/C++/src/nbody.h | 200 +++++++++++++++++++++++ benchmarks/C++/src/nbody/Body.cpp | 87 ---------- benchmarks/C++/src/nbody/Body.h | 55 ------- benchmarks/C++/src/nbody/NBodySystem.cpp | 91 ----------- benchmarks/C++/src/nbody/NBodySystem.h | 24 --- benchmarks/C++/src/run.h | 4 + 8 files changed, 204 insertions(+), 317 deletions(-) delete mode 100644 benchmarks/C++/src/NBody.cpp delete mode 100644 benchmarks/C++/src/NBody.h create mode 100644 benchmarks/C++/src/nbody.h delete mode 100644 benchmarks/C++/src/nbody/Body.cpp delete mode 100644 benchmarks/C++/src/nbody/Body.h delete mode 100644 benchmarks/C++/src/nbody/NBodySystem.cpp delete mode 100644 benchmarks/C++/src/nbody/NBodySystem.h diff --git a/benchmarks/C++/src/NBody.cpp b/benchmarks/C++/src/NBody.cpp deleted file mode 100644 index f4f7cdc1..00000000 --- a/benchmarks/C++/src/NBody.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "NBody.h" - -using namespace std; - -namespace nbody { - - bool NBody::verifyResult(double result, int innerIterations) { - if (innerIterations == 250000) { - return result == -0.1690859889909308; - } - if (innerIterations == 1) { - return result == -0.16907495402506745; - } - - cout << "No verification result for " << innerIterations << " found" << endl; - cout << "Result is: " << result << endl; - return false; - } - - - bool NBody::innerBenchmarkLoop(int innerIterations) { - shared_ptr system = make_shared(); - for (int i = 0; i < innerIterations; i++) { - system->advance(0.01); - } - - return verifyResult(system->energy(), innerIterations); - } - - any NBody::benchmark() { - throw Error("Should never be reached"); - } - - bool NBody::verifyResult(any result) { - (void)result; - throw Error("Should never be reached"); - } -} diff --git a/benchmarks/C++/src/NBody.h b/benchmarks/C++/src/NBody.h deleted file mode 100644 index bff5babc..00000000 --- a/benchmarks/C++/src/NBody.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef NBODY -#define NBODY - -#include "Benchmark.h" -#include "nbody/NBodySystem.h" -#include "som/Error.cpp" - -using namespace std; - -namespace nbody { - class NBody : public Benchmark { - private: - bool verifyResult(double result, int innerIterations); - - public: - bool innerBenchmarkLoop(int innerIterations) override; - any benchmark() override; - bool verifyResult(any result) override; - }; -} - -#endif //NBODY \ No newline at end of file diff --git a/benchmarks/C++/src/nbody.h b/benchmarks/C++/src/nbody.h new file mode 100644 index 00000000..13cb862b --- /dev/null +++ b/benchmarks/C++/src/nbody.h @@ -0,0 +1,200 @@ +#pragma once + +#include "benchmark.h" +#include "som/error.h" + +using std::cout; +using std::endl; + +class Body { + private: + constexpr static double PI = 3.141592653589793; + constexpr static double SOLAR_MASS = 4 * PI * PI; + constexpr static double DAYS_PER_YER = 365.24; + + double _x; + double _y; + double _z; + double _vx; + double _vy; + double _vz; + double _mass; + + public: + [[nodiscard]] double getX() const { return _x; } + [[nodiscard]] double getY() const { return _y; } + [[nodiscard]] double getZ() const { return _z; } + + [[nodiscard]] double getVX() const { return _vx; } + [[nodiscard]] double getVY() const { return _vy; } + [[nodiscard]] double getVZ() const { return _vz; } + + [[nodiscard]] double getMass() const { return _mass; } + + void setX(double x) { _x = x; } + void setY(double y) { _y = y; } + void setZ(double z) { _z = z; } + + void setVX(double vx) { _vx = vx; } + void setVY(double vy) { _vy = vy; } + void setVZ(double vz) { _vz = vz; } + + void offsetMomentum(double px, double py, double pz) { + _vx = 0.0 - (px / SOLAR_MASS); + _vy = 0.0 - (py / SOLAR_MASS); + _vz = 0.0 - (pz / SOLAR_MASS); + } + + Body(Body& other) noexcept = default; + + Body(double x, + double y, + double z, + double vx, + double vy, + double vz, + double mass) + : _x(x), + _y(y), + _z(z), + _vx(vx * DAYS_PER_YER), + _vy(vy * DAYS_PER_YER), + _vz(vz * DAYS_PER_YER), + _mass(mass * SOLAR_MASS) {} + + static Body jupiter() { + return {4.84143144246472090e+00, -1.16032004402742839e+00, + -1.03622044471123109e-01, 1.66007664274403694e-03, + 7.69901118419740425e-03, -6.90460016972063023e-05, + 9.54791938424326609e-04}; + } + static Body saturn() { + return {8.34336671824457987e+00, 4.12479856412430479e+00, + -4.03523417114321381e-01, -2.76742510726862411e-03, + 4.99852801234917238e-03, 2.30417297573763929e-05, + 2.85885980666130812e-04}; + } + static Body uranus() { + return {1.28943695621391310e+01, -1.51111514016986312e+01, + -2.23307578892655734e-01, 2.96460137564761618e-03, + 2.37847173959480950e-03, -2.96589568540237556e-05, + 4.36624404335156298e-05}; + } + + static Body neptune() { + return {1.53796971148509165e+01, -2.59193146099879641e+01, + 1.79258772950371181e-01, 2.68067772490389322e-03, + 1.62824170038242295e-03, -9.51592254519715870e-05, + 5.15138902046611451e-05}; + } + static Body sun() { return {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0}; } +}; + +class NBodySystem { + private: + int32_t _bodiesSize{5}; + std::array _bodies; + + public: + NBodySystem() : _bodies(createBodies()) {} + + [[nodiscard]] std::array createBodies() const { + std::array bodies = {Body::sun(), Body::jupiter(), Body::saturn(), + Body::uranus(), Body::neptune()}; + + double px = 0.0; + double py = 0.0; + double pz = 0.0; + + for (int32_t i = 0; i < _bodiesSize; i += 1) { + px += bodies.at(i).getVX() * bodies.at(i).getMass(); + py += bodies.at(i).getVY() * bodies.at(i).getMass(); + pz += bodies.at(i).getVZ() * bodies.at(i).getMass(); + } + + bodies.at(0).offsetMomentum(px, py, pz); + + return bodies; + } + void advance(double dt) { + for (int32_t i = 0; i < _bodiesSize; i += 1) { + Body& iBody = _bodies.at(i); + + for (int32_t j = i + 1; j < _bodiesSize; j += 1) { + Body& jBody = _bodies.at(j); + const double dx = iBody.getX() - jBody.getX(); + const double dy = iBody.getY() - jBody.getY(); + const double dz = iBody.getZ() - jBody.getZ(); + + const double dSquared = dx * dx + dy * dy + dz * dz; + const double distance = sqrt(dSquared); + const double mag = dt / (dSquared * distance); + + iBody.setVX(iBody.getVX() - (dx * jBody.getMass() * mag)); + iBody.setVY(iBody.getVY() - (dy * jBody.getMass() * mag)); + iBody.setVZ(iBody.getVZ() - (dz * jBody.getMass() * mag)); + + jBody.setVX(jBody.getVX() + (dx * iBody.getMass() * mag)); + jBody.setVY(jBody.getVY() + (dy * iBody.getMass() * mag)); + jBody.setVZ(jBody.getVZ() + (dz * iBody.getMass() * mag)); + } + } + + for (int32_t i = 0; i < _bodiesSize; i += 1) { + _bodies.at(i).setX(_bodies.at(i).getX() + dt * _bodies.at(i).getVX()); + _bodies.at(i).setY(_bodies.at(i).getY() + dt * _bodies.at(i).getVY()); + _bodies.at(i).setZ(_bodies.at(i).getZ() + dt * _bodies.at(i).getVZ()); + } + } + + double energy() { + double e = 0.0; + + for (int32_t i = 0; i < _bodiesSize; i += 1) { + const Body& iBody = _bodies.at(i); + e += 0.5 * iBody.getMass() * + (iBody.getVX() * iBody.getVX() + iBody.getVY() * iBody.getVY() + + iBody.getVZ() * iBody.getVZ()); + + for (int32_t j = i + 1; j < _bodiesSize; j += 1) { + const Body& jBody = _bodies.at(j); + const double dx = iBody.getX() - jBody.getX(); + const double dy = iBody.getY() - jBody.getY(); + const double dz = iBody.getZ() - jBody.getZ(); + + const double distance = sqrt(dx * dx + dy * dy + dz * dz); + e -= (iBody.getMass() * jBody.getMass()) / distance; + } + } + return e; + } +}; + +class NBody : public Benchmark { + private: + bool verify_result(double result, int32_t innerIterations) { + if (innerIterations == 250000) { + return result == -0.1690859889909308; + } + if (innerIterations == 1) { + return result == -0.16907495402506745; + } + + cout << "No verification result for " << innerIterations << " found" + << endl; + cout << "Result is: " << result << endl; + return false; + } + + public: + bool inner_benchmark_loop(int32_t innerIterations) override { + NBodySystem system{}; + for (int32_t i = 0; i < innerIterations; i += 1) { + system.advance(0.01); + } + + return verify_result(system.energy(), innerIterations); + } + void* benchmark() override { throw Error("Should never be reached"); } + bool verify_result(void*) override { throw Error("Should never be reached"); } +}; diff --git a/benchmarks/C++/src/nbody/Body.cpp b/benchmarks/C++/src/nbody/Body.cpp deleted file mode 100644 index 391f6eca..00000000 --- a/benchmarks/C++/src/nbody/Body.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "Body.h" - -namespace nbody { - - double Body::getX() { return _x; } - double Body::getY() { return _y; } - double Body::getZ() { return _z; } - - double Body::getVX() { return _vx; } - double Body::getVY() { return _vy; } - double Body::getVZ() { return _vz; } - - double Body::getMass() { return _mass; } - - void Body::setX(double x) { _x = x; } - void Body::setY(double y) { _y = y; } - void Body::setZ(double z) { _z = z; } - - void Body::setVX(double vx) { _vx = vx; } - void Body::setVY(double vy) { _vy = vy; } - void Body::setVZ(double vz) { _vz = vz; } - - void Body::offsetMomentum(double px, double py, double pz) { - _vx = 0.0 - (px / SOLAR_MASS); - _vy = 0.0 - (py / SOLAR_MASS); - _vz = 0.0 - (pz / SOLAR_MASS); - } - - Body::Body(double x, double y, double z, - double vx, double vy, double vz, double mass) { - _x = x; - _y = y; - _z = z; - _vx = vx * DAYS_PER_YER; - _vy = vy * DAYS_PER_YER; - _vz = vz * DAYS_PER_YER; - _mass = mass * SOLAR_MASS; - } - - shared_ptr Body::jupiter() { - return make_shared( - 4.84143144246472090e+00, - -1.16032004402742839e+00, - -1.03622044471123109e-01, - 1.66007664274403694e-03, - 7.69901118419740425e-03, - -6.90460016972063023e-05, - 9.54791938424326609e-04); - } - - shared_ptr Body::saturn() { - return make_shared( - 8.34336671824457987e+00, - 4.12479856412430479e+00, - -4.03523417114321381e-01, - -2.76742510726862411e-03, - 4.99852801234917238e-03, - 2.30417297573763929e-05, - 2.85885980666130812e-04); - } - - shared_ptr Body::uranus() { - return make_shared( - 1.28943695621391310e+01, - -1.51111514016986312e+01, - -2.23307578892655734e-01, - 2.96460137564761618e-03, - 2.37847173959480950e-03, - -2.96589568540237556e-05, - 4.36624404335156298e-05); - } - - shared_ptr Body::neptune() { - return make_shared( - 1.53796971148509165e+01, - -2.59193146099879641e+01, - 1.79258772950371181e-01, - 2.68067772490389322e-03, - 1.62824170038242295e-03, - -9.51592254519715870e-05, - 5.15138902046611451e-05); - } - - shared_ptr Body::sun() { - return make_shared(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); - } -} diff --git a/benchmarks/C++/src/nbody/Body.h b/benchmarks/C++/src/nbody/Body.h deleted file mode 100644 index 3b5d0c66..00000000 --- a/benchmarks/C++/src/nbody/Body.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef BODY -#define BODY - -#include - -using namespace std; - -namespace nbody { - class Body { - private: - constexpr static double PI = 3.141592653589793; - constexpr static double SOLAR_MASS = 4 * PI * PI; - constexpr static double DAYS_PER_YER = 365.24; - - double _x; - double _y; - double _z; - double _vx; - double _vy; - double _vz; - double _mass; - - public: - - double getX(); - double getY(); - double getZ(); - - double getVX(); - double getVY(); - double getVZ(); - - double getMass(); - - void setX(double x); - void setY(double y); - void setZ(double z); - - void setVX(double vx); - void setVY(double vy); - void setVZ(double vz); - - void offsetMomentum(double px, double py, double pz); - Body(double x, double y, double z, - double vx, double vy, double vz, double mass); - - static shared_ptr jupiter(); - static shared_ptr saturn(); - static shared_ptr uranus(); - static shared_ptr neptune(); - static shared_ptr sun(); - }; -} - -#endif //BODY \ No newline at end of file diff --git a/benchmarks/C++/src/nbody/NBodySystem.cpp b/benchmarks/C++/src/nbody/NBodySystem.cpp deleted file mode 100644 index 11e61a1a..00000000 --- a/benchmarks/C++/src/nbody/NBodySystem.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "NBodySystem.h" - -using namespace std; - -namespace nbody { - NBodySystem::NBodySystem() { - _bodiesSize = 5; - _bodies = createBodies(); - } - - shared_ptr* NBodySystem::createBodies() { - shared_ptr* bodies = new shared_ptr[5]; - bodies[0] = Body::sun(); - bodies[1] = Body::jupiter(); - bodies[2] = Body::saturn(); - bodies[3] = Body::uranus(); - bodies[4] = Body::neptune(); - - double px = 0.0; - double py = 0.0; - double pz = 0.0; - - for (int i = 0; i < _bodiesSize; ++i) { - px += bodies[i]->getVX() * bodies[i]->getMass(); - py += bodies[i]->getVY() * bodies[i]->getMass(); - pz += bodies[i]->getVZ() * bodies[i]->getMass(); - } - - bodies[0]->offsetMomentum(px, py, pz); - - return bodies; - } - - void NBodySystem::advance(double dt) { - for (int i = 0; i < _bodiesSize; ++i) { - shared_ptr iBody = _bodies[i]; - - for (int j = i + 1; j < _bodiesSize; ++j) { - shared_ptr jBody = _bodies[j]; - double dx = iBody->getX() - jBody->getX(); - double dy = iBody->getY() - jBody->getY(); - double dz = iBody->getZ() - jBody->getZ(); - - double dSquared = dx * dx + dy * dy + dz * dz; - double distance = sqrt(dSquared); - double mag = dt / (dSquared * distance); - - iBody->setVX(iBody->getVX() - (dx * jBody->getMass() * mag)); - iBody->setVY(iBody->getVY() - (dy * jBody->getMass() * mag)); - iBody->setVZ(iBody->getVZ() - (dz * jBody->getMass() * mag)); - - jBody->setVX(jBody->getVX() + (dx * iBody->getMass() * mag)); - jBody->setVY(jBody->getVY() + (dy * iBody->getMass() * mag)); - jBody->setVZ(jBody->getVZ() + (dz * iBody->getMass() * mag)); - } - } - - for (int i = 0; i < _bodiesSize; ++i) { - _bodies[i]->setX(_bodies[i]->getX() + dt * _bodies[i]->getVX()); - _bodies[i]->setY(_bodies[i]->getY() + dt * _bodies[i]->getVY()); - _bodies[i]->setZ(_bodies[i]->getZ() + dt * _bodies[i]->getVZ()); - } - } - - double NBodySystem::energy() { - double e = 0.0; - - for (int i = 0; i < _bodiesSize; ++i) { - shared_ptr iBody = _bodies[i]; - e += 0.5 * iBody->getMass() - * (iBody->getVX() * iBody->getVX() + - iBody->getVY() * iBody->getVY() + - iBody->getVZ() * iBody->getVZ()); - - for (int j = i + 1; j < _bodiesSize; ++j) { - shared_ptr jBody = _bodies[j]; - double dx = iBody->getX() - jBody->getX(); - double dy = iBody->getY() - jBody->getY(); - double dz = iBody->getZ() - jBody->getZ(); - - double distance = sqrt(dx * dx + dy * dy + dz * dz); - e -= (iBody->getMass() * jBody->getMass()) / distance; - } - } - delete[] _bodies; - return e; - } - -} - - \ No newline at end of file diff --git a/benchmarks/C++/src/nbody/NBodySystem.h b/benchmarks/C++/src/nbody/NBodySystem.h deleted file mode 100644 index 119c694a..00000000 --- a/benchmarks/C++/src/nbody/NBodySystem.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef NBODYSYSTEM -#define NBODYSYSTEM - -#include "Body.h" -#include - -using namespace std; - -namespace nbody { - class NBodySystem { - private: - shared_ptr* _bodies; - int _bodiesSize; - - public: - NBodySystem(); - - shared_ptr* createBodies(); - void advance(double dt); - double energy(); - }; -} - -#endif //NBODYSYSTEM \ No newline at end of file diff --git a/benchmarks/C++/src/run.h b/benchmarks/C++/src/run.h index a8132267..55bcf489 100644 --- a/benchmarks/C++/src/run.h +++ b/benchmarks/C++/src/run.h @@ -6,6 +6,7 @@ #include "bounce.h" #include "deltablue.h" #include "mandelbrot.h" +#include "nbody.h" #include "permute.h" #include "queens.h" #include "sieve.h" @@ -55,6 +56,9 @@ class Run { if (name == "Mandelbrot") { return []() -> Benchmark* { return new Mandelbrot(); }; } + if (name == "NBody") { + return []() -> Benchmark* { return new NBody(); }; + } if (name == "Permute") { return []() -> Benchmark* { return new Permute(); }; } From 0342615e8d4748613ce73ce58a92f25d4df43e87 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 5 Jan 2024 17:24:16 +0000 Subject: [PATCH 09/40] [C++] Port List benchmark directly from Java Seemed simpler than adopting the available alternatives, especially since I think freeing the linked lists directly seems like a suitable approach for memory management. Signed-off-by: Stefan Marr --- benchmarks/C++/src/list.h | 85 +++++++++++++++++++++++++++++++++++++++ benchmarks/C++/src/run.h | 4 ++ 2 files changed, 89 insertions(+) create mode 100644 benchmarks/C++/src/list.h diff --git a/benchmarks/C++/src/list.h b/benchmarks/C++/src/list.h new file mode 100644 index 00000000..d6805e8a --- /dev/null +++ b/benchmarks/C++/src/list.h @@ -0,0 +1,85 @@ +#pragma once + +#include + +#include "benchmark.h" + +class Element { + private: + std::any val; + Element* next{nullptr}; + + public: + explicit Element(std::any v) : val(std::move(v)) {} + + ~Element() { + if (next != nullptr) { + delete next; + } + } + + [[nodiscard]] int32_t length() { + if (next == nullptr) { + return 1; + } + return 1 + next->length(); + } + + [[nodiscard]] std::any getVal() const { return val; } + void setVal(std::any v) { val = std::move(v); } + [[nodiscard]] Element* getNext() const { return next; } + void setNext(Element* e) { next = e; } +}; + +class List : public Benchmark { + public: + void* benchmark() override { + Element* x = makeList(15); + Element* y = makeList(10); + Element* z = makeList(6); + + Element* result = tail(x, y, z); + const int32_t l = result->length(); + + delete x; + delete y; + delete z; + return reinterpret_cast(static_cast(l)); + } + + private: + [[nodiscard]] Element* makeList(int32_t length) const { + if (length == 0) { + return nullptr; + } + auto* e = new Element(length); + e->setNext(makeList(length - 1)); + return e; + } + + [[nodiscard]] bool isShorterThan(Element* x, Element* y) const { + Element* xTail = x; + Element* yTail = y; + + while (yTail != nullptr) { + if (xTail == nullptr) { + return true; + } + xTail = xTail->getNext(); + yTail = yTail->getNext(); + } + return false; + } + + Element* tail(Element* x, Element* y, Element* z) { + if (isShorterThan(y, x)) { + return tail(tail(x->getNext(), y, z), tail(y->getNext(), z, x), + tail(z->getNext(), x, y)); + } + return z; + } + + bool verify_result(void* result) override { + return 10 == static_cast(reinterpret_cast(result)); + } +}; diff --git a/benchmarks/C++/src/run.h b/benchmarks/C++/src/run.h index 55bcf489..4a84f150 100644 --- a/benchmarks/C++/src/run.h +++ b/benchmarks/C++/src/run.h @@ -5,6 +5,7 @@ #include "bounce.h" #include "deltablue.h" +#include "list.h" #include "mandelbrot.h" #include "nbody.h" #include "permute.h" @@ -53,6 +54,9 @@ class Run { if (name == "Bounce") { return []() -> Benchmark* { return new Bounce(); }; } + if (name == "List") { + return []() -> Benchmark* { return new List(); }; + } if (name == "Mandelbrot") { return []() -> Benchmark* { return new Mandelbrot(); }; } From f6d247fad3c9d2289eabf96a9ada8bd3fde42be5 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 5 Jan 2024 22:21:19 +0000 Subject: [PATCH 10/40] [C++] Added Json port by Hugo Jenningros Signed-off-by: Stefan Marr --- benchmarks/C++/src/Json.cpp | 27 ++ benchmarks/C++/src/Json.h | 18 ++ benchmarks/C++/src/json/JsonArray.cpp | 30 ++ benchmarks/C++/src/json/JsonArray.h | 26 ++ benchmarks/C++/src/json/JsonLiteral.cpp | 42 +++ benchmarks/C++/src/json/JsonLiteral.h | 29 ++ benchmarks/C++/src/json/JsonNumber.cpp | 20 ++ benchmarks/C++/src/json/JsonNumber.h | 23 ++ benchmarks/C++/src/json/JsonObject.cpp | 53 +++ benchmarks/C++/src/json/JsonObject.h | 34 ++ .../C++/src/json/JsonPureStringParser.cpp | 305 ++++++++++++++++++ .../C++/src/json/JsonPureStringParser.h | 64 ++++ benchmarks/C++/src/json/JsonString.cpp | 13 + benchmarks/C++/src/json/JsonString.h | 21 ++ benchmarks/C++/src/json/JsonValue.cpp | 55 ++++ benchmarks/C++/src/json/JsonValue.h | 32 ++ benchmarks/C++/src/json/ParseException.cpp | 27 ++ benchmarks/C++/src/json/ParseException.h | 26 ++ 18 files changed, 845 insertions(+) create mode 100644 benchmarks/C++/src/Json.cpp create mode 100644 benchmarks/C++/src/Json.h create mode 100644 benchmarks/C++/src/json/JsonArray.cpp create mode 100644 benchmarks/C++/src/json/JsonArray.h create mode 100644 benchmarks/C++/src/json/JsonLiteral.cpp create mode 100644 benchmarks/C++/src/json/JsonLiteral.h create mode 100644 benchmarks/C++/src/json/JsonNumber.cpp create mode 100644 benchmarks/C++/src/json/JsonNumber.h create mode 100644 benchmarks/C++/src/json/JsonObject.cpp create mode 100644 benchmarks/C++/src/json/JsonObject.h create mode 100644 benchmarks/C++/src/json/JsonPureStringParser.cpp create mode 100644 benchmarks/C++/src/json/JsonPureStringParser.h create mode 100644 benchmarks/C++/src/json/JsonString.cpp create mode 100644 benchmarks/C++/src/json/JsonString.h create mode 100644 benchmarks/C++/src/json/JsonValue.cpp create mode 100644 benchmarks/C++/src/json/JsonValue.h create mode 100644 benchmarks/C++/src/json/ParseException.cpp create mode 100644 benchmarks/C++/src/json/ParseException.h diff --git a/benchmarks/C++/src/Json.cpp b/benchmarks/C++/src/Json.cpp new file mode 100644 index 00000000..6aaa6598 --- /dev/null +++ b/benchmarks/C++/src/Json.cpp @@ -0,0 +1,27 @@ +#include "Json.h" + +using namespace std; + +namespace json { + + any Json::benchmark() { + return (make_shared(rapBenchmarkMinified))->parse(); + } + + bool Json::verifyResult(any r) { + shared_ptr result = any_cast>(r); + if (!result->isObject()) { + return false; + } + shared_ptr resultObject = result->asObject(); + if (!resultObject->get("head")->isObject()) { + return false; + } + if (!resultObject->get("operations")->isArray()) { + return false; + } + shared_ptr resultArray = resultObject->get("operations")->asArray(); + return resultArray->size() == 156; + } + +} \ No newline at end of file diff --git a/benchmarks/C++/src/Json.h b/benchmarks/C++/src/Json.h new file mode 100644 index 00000000..61a6fa85 --- /dev/null +++ b/benchmarks/C++/src/Json.h @@ -0,0 +1,18 @@ +#include "Benchmark.h" +#include "json/JsonPureStringParser.h" +#include + +using namespace std; + +namespace json { + class Json : public Benchmark { + private: + string rapBenchmarkMinified = "{\"head\":{\"requestCounter\":4},\"operations\":[[\"destroy\",\"w54\"],[\"set\",\"w2\",{\"activeControl\":\"w99\"}],[\"set\",\"w21\",{\"customVariant\":\"variant_navigation\"}],[\"set\",\"w28\",{\"customVariant\":\"variant_selected\"}],[\"set\",\"w53\",{\"children\":[\"w95\"]}],[\"create\",\"w95\",\"rwt.widgets.Composite\",{\"parent\":\"w53\",\"style\":[\"NONE\"],\"bounds\":[0,0,1008,586],\"children\":[\"w96\",\"w97\"],\"tabIndex\":-1,\"clientArea\":[0,0,1008,586]}],[\"create\",\"w96\",\"rwt.widgets.Label\",{\"parent\":\"w95\",\"style\":[\"NONE\"],\"bounds\":[10,30,112,26],\"tabIndex\":-1,\"customVariant\":\"variant_pageHeadline\",\"text\":\"TableViewer\"}],[\"create\",\"w97\",\"rwt.widgets.Composite\",{\"parent\":\"w95\",\"style\":[\"NONE\"],\"bounds\":[0,61,1008,525],\"children\":[\"w98\",\"w99\",\"w226\",\"w228\"],\"tabIndex\":-1,\"clientArea\":[0,0,1008,525]}],[\"create\",\"w98\",\"rwt.widgets.Text\",{\"parent\":\"w97\",\"style\":[\"LEFT\",\"SINGLE\",\"BORDER\"],\"bounds\":[10,10,988,32],\"tabIndex\":22,\"activeKeys\":[\"#13\",\"#27\",\"#40\"]}],[\"listen\",\"w98\",{\"KeyDown\":true,\"Modify\":true}],[\"create\",\"w99\",\"rwt.widgets.Grid\",{\"parent\":\"w97\",\"style\":[\"SINGLE\",\"BORDER\"],\"appearance\":\"table\",\"indentionWidth\":0,\"treeColumn\":-1,\"markupEnabled\":false}],[\"create\",\"w100\",\"rwt.widgets.ScrollBar\",{\"parent\":\"w99\",\"style\":[\"HORIZONTAL\"]}],[\"create\",\"w101\",\"rwt.widgets.ScrollBar\",{\"parent\":\"w99\",\"style\":[\"VERTICAL\"]}],[\"set\",\"w99\",{\"bounds\":[10,52,988,402],\"children\":[],\"tabIndex\":23,\"activeKeys\":[\"CTRL+#70\",\"CTRL+#78\",\"CTRL+#82\",\"CTRL+#89\",\"CTRL+#83\",\"CTRL+#71\",\"CTRL+#69\"],\"cancelKeys\":[\"CTRL+#70\",\"CTRL+#78\",\"CTRL+#82\",\"CTRL+#89\",\"CTRL+#83\",\"CTRL+#71\",\"CTRL+#69\"]}],[\"listen\",\"w99\",{\"MouseDown\":true,\"MouseUp\":true,\"MouseDoubleClick\":true,\"KeyDown\":true}],[\"set\",\"w99\",{\"itemCount\":118,\"itemHeight\":28,\"itemMetrics\":[[0,0,50,3,0,3,44],[1,50,50,53,0,53,44],[2,100,140,103,0,103,134],[3,240,180,243,0,243,174],[4,420,50,423,0,423,44],[5,470,50,473,0,473,44]],\"columnCount\":6,\"headerHeight\":35,\"headerVisible\":true,\"linesVisible\":true,\"focusItem\":\"w108\",\"selection\":[\"w108\"]}],[\"listen\",\"w99\",{\"Selection\":true,\"DefaultSelection\":true}],[\"set\",\"w99\",{\"enableCellToolTip\":true}],[\"listen\",\"w100\",{\"Selection\":true}],[\"set\",\"w101\",{\"visibility\":true}],[\"listen\",\"w101\",{\"Selection\":true}],[\"create\",\"w102\",\"rwt.widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Nr.\",\"width\":50,\"moveable\":true}],[\"listen\",\"w102\",{\"Selection\":true}],[\"create\",\"w103\",\"rwt.widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Sym.\",\"index\":1,\"left\":50,\"width\":50,\"moveable\":true}],[\"listen\",\"w103\",{\"Selection\":true}],[\"create\",\"w104\",\"rwt.widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Name\",\"index\":2,\"left\":100,\"width\":140,\"moveable\":true}],[\"listen\",\"w104\",{\"Selection\":true}],[\"create\",\"w105\",\"rwt.widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Series\",\"index\":3,\"left\":240,\"width\":180,\"moveable\":true}],[\"listen\",\"w105\",{\"Selection\":true}],[\"create\",\"w106\",\"rwt.widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Group\",\"index\":4,\"left\":420,\"width\":50,\"moveable\":true}],[\"listen\",\"w106\",{\"Selection\":true}],[\"create\",\"w107\",\"rwt.widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Period\",\"index\":5,\"left\":470,\"width\":50,\"moveable\":true}],[\"listen\",\"w107\",{\"Selection\":true}],[\"create\",\"w108\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":0,\"texts\":[\"1\",\"H\",\"Hydrogen\",\"Nonmetal\",\"1\",\"1\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w109\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":1,\"texts\":[\"2\",\"He\",\"Helium\",\"Noble gas\",\"18\",\"1\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w110\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":2,\"texts\":[\"3\",\"Li\",\"Lithium\",\"Alkali metal\",\"1\",\"2\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255],null,null]}],[\"create\",\"w111\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":3,\"texts\":[\"4\",\"Be\",\"Beryllium\",\"Alkaline earth metal\",\"2\",\"2\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255],null,null]}],[\"create\",\"w112\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":4,\"texts\":[\"5\",\"B\",\"Boron\",\"Metalloid\",\"13\",\"2\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w113\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":5,\"texts\":[\"6\",\"C\",\"Carbon\",\"Nonmetal\",\"14\",\"2\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w114\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":6,\"texts\":[\"7\",\"N\",\"Nitrogen\",\"Nonmetal\",\"15\",\"2\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w115\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":7,\"texts\":[\"8\",\"O\",\"Oxygen\",\"Nonmetal\",\"16\",\"2\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w116\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":8,\"texts\":[\"9\",\"F\",\"Fluorine\",\"Halogen\",\"17\",\"2\"],\"cellBackgrounds\":[null,null,null,[252,233,79,255],null,null]}],[\"create\",\"w117\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":9,\"texts\":[\"10\",\"Ne\",\"Neon\",\"Noble gas\",\"18\",\"2\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w118\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":10,\"texts\":[\"11\",\"Na\",\"Sodium\",\"Alkali metal\",\"1\",\"3\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255],null,null]}],[\"create\",\"w119\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":11,\"texts\":[\"12\",\"Mg\",\"Magnesium\",\"Alkaline earth metal\",\"2\",\"3\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255],null,null]}],[\"create\",\"w120\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":12,\"texts\":[\"13\",\"Al\",\"Aluminium\",\"Poor metal\",\"13\",\"3\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w121\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":13,\"texts\":[\"14\",\"Si\",\"Silicon\",\"Metalloid\",\"14\",\"3\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w122\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":14,\"texts\":[\"15\",\"P\",\"Phosphorus\",\"Nonmetal\",\"15\",\"3\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w123\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":15,\"texts\":[\"16\",\"S\",\"Sulfur\",\"Nonmetal\",\"16\",\"3\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w124\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":16,\"texts\":[\"17\",\"Cl\",\"Chlorine\",\"Halogen\",\"17\",\"3\"],\"cellBackgrounds\":[null,null,null,[252,233,79,255],null,null]}],[\"create\",\"w125\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":17,\"texts\":[\"18\",\"Ar\",\"Argon\",\"Noble gas\",\"18\",\"3\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w126\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":18,\"texts\":[\"19\",\"K\",\"Potassium\",\"Alkali metal\",\"1\",\"4\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255],null,null]}],[\"create\",\"w127\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":19,\"texts\":[\"20\",\"Ca\",\"Calcium\",\"Alkaline earth metal\",\"2\",\"4\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255],null,null]}],[\"create\",\"w128\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":20,\"texts\":[\"21\",\"Sc\",\"Scandium\",\"Transition metal\",\"3\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w129\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":21,\"texts\":[\"22\",\"Ti\",\"Titanium\",\"Transition metal\",\"4\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w130\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":22,\"texts\":[\"23\",\"V\",\"Vanadium\",\"Transition metal\",\"5\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w131\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":23,\"texts\":[\"24\",\"Cr\",\"Chromium\",\"Transition metal\",\"6\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w132\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":24,\"texts\":[\"25\",\"Mn\",\"Manganese\",\"Transition metal\",\"7\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w133\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":25,\"texts\":[\"26\",\"Fe\",\"Iron\",\"Transition metal\",\"8\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w134\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":26,\"texts\":[\"27\",\"Co\",\"Cobalt\",\"Transition metal\",\"9\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w135\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":27,\"texts\":[\"28\",\"Ni\",\"Nickel\",\"Transition metal\",\"10\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w136\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":28,\"texts\":[\"29\",\"Cu\",\"Copper\",\"Transition metal\",\"11\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w137\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":29,\"texts\":[\"30\",\"Zn\",\"Zinc\",\"Transition metal\",\"12\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w138\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":30,\"texts\":[\"31\",\"Ga\",\"Gallium\",\"Poor metal\",\"13\",\"4\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w139\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":31,\"texts\":[\"32\",\"Ge\",\"Germanium\",\"Metalloid\",\"14\",\"4\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w140\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":32,\"texts\":[\"33\",\"As\",\"Arsenic\",\"Metalloid\",\"15\",\"4\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w141\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":33,\"texts\":[\"34\",\"Se\",\"Selenium\",\"Nonmetal\",\"16\",\"4\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w142\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":34,\"texts\":[\"35\",\"Br\",\"Bromine\",\"Halogen\",\"17\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,233,79,255],null,null]}],[\"create\",\"w143\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":35,\"texts\":[\"36\",\"Kr\",\"Krypton\",\"Noble gas\",\"18\",\"4\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w144\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":36,\"texts\":[\"37\",\"Rb\",\"Rubidium\",\"Alkali metal\",\"1\",\"5\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255],null,null]}],[\"create\",\"w145\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":37,\"texts\":[\"38\",\"Sr\",\"Strontium\",\"Alkaline earth metal\",\"2\",\"5\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255],null,null]}],[\"create\",\"w146\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":38,\"texts\":[\"39\",\"Y\",\"Yttrium\",\"Transition metal\",\"3\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w147\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":39,\"texts\":[\"40\",\"Zr\",\"Zirconium\",\"Transition metal\",\"4\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w148\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":40,\"texts\":[\"41\",\"Nb\",\"Niobium\",\"Transition metal\",\"5\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w149\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":41,\"texts\":[\"42\",\"Mo\",\"Molybdenum\",\"Transition metal\",\"6\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w150\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":42,\"texts\":[\"43\",\"Tc\",\"Technetium\",\"Transition metal\",\"7\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w151\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":43,\"texts\":[\"44\",\"Ru\",\"Ruthenium\",\"Transition metal\",\"8\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w152\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":44,\"texts\":[\"45\",\"Rh\",\"Rhodium\",\"Transition metal\",\"9\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w153\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":45,\"texts\":[\"46\",\"Pd\",\"Palladium\",\"Transition metal\",\"10\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w154\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":46,\"texts\":[\"47\",\"Ag\",\"Silver\",\"Transition metal\",\"11\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w155\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":47,\"texts\":[\"48\",\"Cd\",\"Cadmium\",\"Transition metal\",\"12\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w156\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":48,\"texts\":[\"49\",\"In\",\"Indium\",\"Poor metal\",\"13\",\"5\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w157\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":49,\"texts\":[\"50\",\"Sn\",\"Tin\",\"Poor metal\",\"14\",\"5\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w158\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":50,\"texts\":[\"51\",\"Sb\",\"Antimony\",\"Metalloid\",\"15\",\"5\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w159\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":51,\"texts\":[\"52\",\"Te\",\"Tellurium\",\"Metalloid\",\"16\",\"5\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w160\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":52,\"texts\":[\"53\",\"I\",\"Iodine\",\"Halogen\",\"17\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,233,79,255],null,null]}],[\"create\",\"w161\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":53,\"texts\":[\"54\",\"Xe\",\"Xenon\",\"Noble gas\",\"18\",\"5\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w162\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":54,\"texts\":[\"55\",\"Cs\",\"Caesium\",\"Alkali metal\",\"1\",\"6\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255],null,null]}],[\"create\",\"w163\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":55,\"texts\":[\"56\",\"Ba\",\"Barium\",\"Alkaline earth metal\",\"2\",\"6\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255],null,null]}],[\"create\",\"w164\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":56,\"texts\":[\"57\",\"La\",\"Lanthanum\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w165\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":57,\"texts\":[\"58\",\"Ce\",\"Cerium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w166\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":58,\"texts\":[\"59\",\"Pr\",\"Praseodymium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w167\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":59,\"texts\":[\"60\",\"Nd\",\"Neodymium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w168\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":60,\"texts\":[\"61\",\"Pm\",\"Promethium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w169\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":61,\"texts\":[\"62\",\"Sm\",\"Samarium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w170\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":62,\"texts\":[\"63\",\"Eu\",\"Europium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w171\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":63,\"texts\":[\"64\",\"Gd\",\"Gadolinium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w172\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":64,\"texts\":[\"65\",\"Tb\",\"Terbium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w173\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":65,\"texts\":[\"66\",\"Dy\",\"Dysprosium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w174\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":66,\"texts\":[\"67\",\"Ho\",\"Holmium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w175\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":67,\"texts\":[\"68\",\"Er\",\"Erbium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w176\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":68,\"texts\":[\"69\",\"Tm\",\"Thulium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w177\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":69,\"texts\":[\"70\",\"Yb\",\"Ytterbium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w178\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":70,\"texts\":[\"71\",\"Lu\",\"Lutetium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w179\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":71,\"texts\":[\"72\",\"Hf\",\"Hafnium\",\"Transition metal\",\"4\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w180\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":72,\"texts\":[\"73\",\"Ta\",\"Tantalum\",\"Transition metal\",\"5\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w181\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":73,\"texts\":[\"74\",\"W\",\"Tungsten\",\"Transition metal\",\"6\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w182\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":74,\"texts\":[\"75\",\"Re\",\"Rhenium\",\"Transition metal\",\"7\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w183\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":75,\"texts\":[\"76\",\"Os\",\"Osmium\",\"Transition metal\",\"8\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w184\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":76,\"texts\":[\"77\",\"Ir\",\"Iridium\",\"Transition metal\",\"9\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w185\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":77,\"texts\":[\"78\",\"Pt\",\"Platinum\",\"Transition metal\",\"10\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w186\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":78,\"texts\":[\"79\",\"Au\",\"Gold\",\"Transition metal\",\"11\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w187\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":79,\"texts\":[\"80\",\"Hg\",\"Mercury\",\"Transition metal\",\"12\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w188\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":80,\"texts\":[\"81\",\"Tl\",\"Thallium\",\"Poor metal\",\"13\",\"6\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w189\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":81,\"texts\":[\"82\",\"Pb\",\"Lead\",\"Poor metal\",\"14\",\"6\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w190\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":82,\"texts\":[\"83\",\"Bi\",\"Bismuth\",\"Poor metal\",\"15\",\"6\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w191\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":83,\"texts\":[\"84\",\"Po\",\"Polonium\",\"Metalloid\",\"16\",\"6\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w192\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":84,\"texts\":[\"85\",\"At\",\"Astatine\",\"Halogen\",\"17\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,233,79,255],null,null]}],[\"create\",\"w193\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":85,\"texts\":[\"86\",\"Rn\",\"Radon\",\"Noble gas\",\"18\",\"6\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w194\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":86,\"texts\":[\"87\",\"Fr\",\"Francium\",\"Alkali metal\",\"1\",\"7\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255],null,null]}],[\"create\",\"w195\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":87,\"texts\":[\"88\",\"Ra\",\"Radium\",\"Alkaline earth metal\",\"2\",\"7\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255],null,null]}],[\"create\",\"w196\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":88,\"texts\":[\"89\",\"Ac\",\"Actinium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w197\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":89,\"texts\":[\"90\",\"Th\",\"Thorium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w198\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":90,\"texts\":[\"91\",\"Pa\",\"Protactinium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w199\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":91,\"texts\":[\"92\",\"U\",\"Uranium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w200\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":92,\"texts\":[\"93\",\"Np\",\"Neptunium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w201\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":93,\"texts\":[\"94\",\"Pu\",\"Plutonium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w202\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":94,\"texts\":[\"95\",\"Am\",\"Americium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w203\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":95,\"texts\":[\"96\",\"Cm\",\"Curium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w204\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":96,\"texts\":[\"97\",\"Bk\",\"Berkelium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w205\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":97,\"texts\":[\"98\",\"Cf\",\"Californium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w206\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":98,\"texts\":[\"99\",\"Es\",\"Einsteinium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w207\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":99,\"texts\":[\"100\",\"Fm\",\"Fermium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w208\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":100,\"texts\":[\"101\",\"Md\",\"Mendelevium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w209\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":101,\"texts\":[\"102\",\"No\",\"Nobelium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w210\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":102,\"texts\":[\"103\",\"Lr\",\"Lawrencium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w211\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":103,\"texts\":[\"104\",\"Rf\",\"Rutherfordium\",\"Transition metal\",\"4\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w212\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":104,\"texts\":[\"105\",\"Db\",\"Dubnium\",\"Transition metal\",\"5\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w213\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":105,\"texts\":[\"106\",\"Sg\",\"Seaborgium\",\"Transition metal\",\"6\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w214\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":106,\"texts\":[\"107\",\"Bh\",\"Bohrium\",\"Transition metal\",\"7\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w215\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":107,\"texts\":[\"108\",\"Hs\",\"Hassium\",\"Transition metal\",\"8\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w216\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":108,\"texts\":[\"109\",\"Mt\",\"Meitnerium\",\"Transition metal\",\"9\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w217\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":109,\"texts\":[\"110\",\"Ds\",\"Darmstadtium\",\"Transition metal\",\"10\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w218\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":110,\"texts\":[\"111\",\"Rg\",\"Roentgenium\",\"Transition metal\",\"11\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w219\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":111,\"texts\":[\"112\",\"Uub\",\"Ununbium\",\"Transition metal\",\"12\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w220\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":112,\"texts\":[\"113\",\"Uut\",\"Ununtrium\",\"Poor metal\",\"13\",\"7\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w221\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":113,\"texts\":[\"114\",\"Uuq\",\"Ununquadium\",\"Poor metal\",\"14\",\"7\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w222\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":114,\"texts\":[\"115\",\"Uup\",\"Ununpentium\",\"Poor metal\",\"15\",\"7\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w223\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":115,\"texts\":[\"116\",\"Uuh\",\"Ununhexium\",\"Poor metal\",\"16\",\"7\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w224\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":116,\"texts\":[\"117\",\"Uus\",\"Ununseptium\",\"Halogen\",\"17\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,233,79,255],null,null]}],[\"create\",\"w225\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":117,\"texts\":[\"118\",\"Uuo\",\"Ununoctium\",\"Noble gas\",\"18\",\"7\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w226\",\"rwt.widgets.Composite\",{\"parent\":\"w97\",\"style\":[\"BORDER\"],\"bounds\":[10,464,988,25],\"children\":[\"w227\"],\"tabIndex\":-1,\"clientArea\":[0,0,986,23]}],[\"create\",\"w227\",\"rwt.widgets.Label\",{\"parent\":\"w226\",\"style\":[\"NONE\"],\"bounds\":[10,10,966,3],\"tabIndex\":-1,\"text\":\"Hydrogen (H)\"}],[\"create\",\"w228\",\"rwt.widgets.Label\",{\"parent\":\"w97\",\"style\":[\"WRAP\"],\"bounds\":[10,499,988,16],\"tabIndex\":-1,\"foreground\":[150,150,150,255],\"font\":[[\"Verdana\",\"Lucida Sans\",\"Arial\",\"Helvetica\",\"sans-serif\"],10,false,false],\"text\":\"Shortcuts: [CTRL+F] - Filter | Sort by: [CTRL+R] - Number, [CTRL+Y] - Symbol, [CTRL+N] - Name, [CTRL+S] - Series, [CTRL+G] - Group, [CTRL+E] - Period\"}],[\"set\",\"w1\",{\"focusControl\":\"w99\"}],[\"call\",\"rwt.client.BrowserNavigation\",\"addToHistory\",{\"entries\":[[\"tableviewer\",\"TableViewer\"]]}]]}"; + + + public: + any benchmark() override; + bool verifyResult(any r) override; + + }; +} \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonArray.cpp b/benchmarks/C++/src/json/JsonArray.cpp new file mode 100644 index 00000000..b6adf787 --- /dev/null +++ b/benchmarks/C++/src/json/JsonArray.cpp @@ -0,0 +1,30 @@ +#include "JsonArray.h" + +namespace json { + JsonArray::JsonArray() { + _values = make_shared>>(); + } + + void JsonArray::add(shared_ptr value) { + if (value == nullptr) { + throw Error("value is null"); + } + _values->append(value); + } + + int JsonArray::size() { + return _values->size(); + } + + shared_ptr JsonArray::get(int index) { + return _values->at(index); + } + + bool JsonArray::isArray() { + return true; + } + + shared_ptr JsonArray::asArray() { + return shared_from_this(); + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonArray.h b/benchmarks/C++/src/json/JsonArray.h new file mode 100644 index 00000000..f898257a --- /dev/null +++ b/benchmarks/C++/src/json/JsonArray.h @@ -0,0 +1,26 @@ +#ifndef JSONARRAY +#define JSONARRAY + +#include "../som/Vector.cpp" +#include "JsonValue.h" +#include +#include "../som/Error.cpp" + +namespace json { + class JsonArray : public JsonValue, public std::enable_shared_from_this { + private: + shared_ptr>> _values; + + public: + + JsonArray(); + + void add(shared_ptr value); + int size(); + shared_ptr get(int index); + bool isArray() override; + shared_ptr asArray() override; + }; +} + +#endif //JSONARRAY \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonLiteral.cpp b/benchmarks/C++/src/json/JsonLiteral.cpp new file mode 100644 index 00000000..db35d0dc --- /dev/null +++ b/benchmarks/C++/src/json/JsonLiteral.cpp @@ -0,0 +1,42 @@ +#include "JsonLiteral.h" + + +namespace json { + + shared_ptr JsonLiteral::NNULL = make_shared("null"); + shared_ptr JsonLiteral::TRUE = make_shared("true"); + shared_ptr JsonLiteral::FALSE = make_shared("false"); + + JsonLiteral::JsonLiteral(string value) { + _value = value; + _isNull = (value == "null"); + _isTrue = (value == "true"); + _isFalse = (value == "false"); + } + + // Method to get the string representation of the literal + string JsonLiteral::toString() { + return _value; + } + + // Check if the literal is null + bool JsonLiteral::isNull() { + return _isNull; + } + + // Check if the literal is true + bool JsonLiteral::isTrue() { + return _isTrue; + } + + // Check if the literal is false + bool JsonLiteral::isFalse() { + return _isFalse; + } + + // Check if the literal is a boolean value (true or false) + bool JsonLiteral::isBoolean() { + return _isTrue || _isFalse; + } + +} \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonLiteral.h b/benchmarks/C++/src/json/JsonLiteral.h new file mode 100644 index 00000000..6f63de87 --- /dev/null +++ b/benchmarks/C++/src/json/JsonLiteral.h @@ -0,0 +1,29 @@ +#include +#include +#include "JsonValue.h" + +using namespace std; + +namespace json { + class JsonLiteral: public JsonValue { + private: + string _value; + bool _isNull; + bool _isTrue; + bool _isFalse; + + public: + static shared_ptr NNULL; + static shared_ptr TRUE; + static shared_ptr FALSE; + + JsonLiteral(string value); + + string toString() override; + bool isNull() override; + bool isTrue() override; + bool isFalse() override; + bool isBoolean() override; + + }; +} diff --git a/benchmarks/C++/src/json/JsonNumber.cpp b/benchmarks/C++/src/json/JsonNumber.cpp new file mode 100644 index 00000000..d28f414a --- /dev/null +++ b/benchmarks/C++/src/json/JsonNumber.cpp @@ -0,0 +1,20 @@ +#include "JsonNumber.h" + +using namespace std; + +namespace json { + JsonNumber::JsonNumber(string string) { + _string = string; + if (string.empty()) { + throw Error("value is null"); + } + } + + string JsonNumber::toString() { + return _string; + } + + bool JsonNumber::isNumber() { + return true; + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonNumber.h b/benchmarks/C++/src/json/JsonNumber.h new file mode 100644 index 00000000..5b9fb11a --- /dev/null +++ b/benchmarks/C++/src/json/JsonNumber.h @@ -0,0 +1,23 @@ +#ifndef JSONUMBER +#define JSONUMBER + +#include +#include "../som/Error.cpp" +#include "JsonValue.h" + +using namespace std; + +namespace json { + class JsonNumber : public JsonValue { + private: + string _string; + + public: + JsonNumber(string string); + + string toString() override; + bool isNumber() override; + }; +} + +#endif //JSONUMBER \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonObject.cpp b/benchmarks/C++/src/json/JsonObject.cpp new file mode 100644 index 00000000..cedd9a0e --- /dev/null +++ b/benchmarks/C++/src/json/JsonObject.cpp @@ -0,0 +1,53 @@ +#include "JsonObject.h" + +namespace json { + JsonObject::JsonObject() { + _names = make_shared>(); + _values = make_shared>>(); + }; + + int JsonObject::indexOf(string name) { + int index = _table.find(name)->second; + if (index != -1 && name == _names->at(index)) { + return index; + } + throw new Error("NotImplemented"); + } + + + void JsonObject::add(string name, shared_ptr value) { + if (name.empty()) { + throw Error ("name is null"); + } + if (value == nullptr) { + throw Error ("value is null"); + } + _table[name] = _names->size(); + _names->append(name); + _values->append(value); + } + + shared_ptr JsonObject::get(string name) { + if (name.empty()) { + throw Error ("name is null"); + } + int index = indexOf(name); + return index == -1 ? nullptr : _values->at(index); + } + + int JsonObject::size() const { + return static_cast(_names->size()); + } + + bool JsonObject::isEmpty() const { + return _names->isEmpty(); + } + + bool JsonObject::isObject() { + return true; + } + + shared_ptr JsonObject::asObject() { + return shared_from_this(); + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonObject.h b/benchmarks/C++/src/json/JsonObject.h new file mode 100644 index 00000000..926a2b2c --- /dev/null +++ b/benchmarks/C++/src/json/JsonObject.h @@ -0,0 +1,34 @@ +#ifndef JSONNUMBER +#define JSONNUMBER + +#include "../som/Vector.cpp" +#include "JsonValue.h" +#include "../som/Error.cpp" +#include +#include +#include + +using namespace std; + +namespace json { + class JsonObject : public JsonValue, public std::enable_shared_from_this { + private: + shared_ptr> _names; + shared_ptr>> _values; + map _table; + + int indexOf(string name); + + public: + JsonObject(); + + void add(string name, shared_ptr value); + shared_ptr get(string name); + int size() const; + bool isEmpty() const; + bool isObject() override; + shared_ptr asObject() override; + }; +} + +#endif //JSONNUMBER diff --git a/benchmarks/C++/src/json/JsonPureStringParser.cpp b/benchmarks/C++/src/json/JsonPureStringParser.cpp new file mode 100644 index 00000000..7804163c --- /dev/null +++ b/benchmarks/C++/src/json/JsonPureStringParser.cpp @@ -0,0 +1,305 @@ +#include "JsonPureStringParser.h" + +namespace json { + + shared_ptr JsonPureStringParser::readValue() { + if (_current == "n") { + return readNull(); + } else if (_current == "t") { + return readTrue(); + } else if (_current == "f") { + return readFalse(); + } else if (_current == "\"") { + return readString(); + } else if (_current == "[") { + return readArray(); + } else if (_current == "{") { + return readObject(); + } + else if (_current == "-" || _current == "0" || _current == "1" || _current == "2" || _current == "3" || _current == "4" + || _current == "5" || _current == "6" || _current == "7" || _current == "8" || _current == "9") { + return readNumber(); + } + else + throw expected("value"); + } + + shared_ptr JsonPureStringParser::readObject() { + read(); + shared_ptr object = make_shared(); + skipWhiteSpace(); + if (readChar("}")) { + return object; + } + do { + skipWhiteSpace(); + string name = readName(); + skipWhiteSpace(); + if (!readChar(":")) { + throw expected("':'"); + } + skipWhiteSpace(); + + object->add(name, readValue()); + skipWhiteSpace(); + } + while (readChar(",")); + if (!readChar("}")) { + throw expected("',' or '}'"); + } + return object; + } + + string JsonPureStringParser::readName() { + if (_current != "\"") { + throw expected("name"); + } + return readStringInternal(); + } + + shared_ptr JsonPureStringParser::readArray() { + read(); + shared_ptr array = make_shared(); + skipWhiteSpace(); + if (readChar("]")) { + return array; + } + do { + skipWhiteSpace(); + array->add(readValue()); + skipWhiteSpace(); + } while (readChar(",")); + + if (!readChar("]")) { + throw expected("',' or ']'"); + } + return array; + } + + shared_ptr JsonPureStringParser::readNull() { + read(); + readRequiredChar("u"); + readRequiredChar("l"); + readRequiredChar("l"); + return JsonLiteral::NNULL; + } + + shared_ptr JsonPureStringParser::readTrue() { + read(); + readRequiredChar("r"); + readRequiredChar("u"); + readRequiredChar("e"); + return JsonLiteral::TRUE; + } + + shared_ptr JsonPureStringParser::readFalse() { + read(); + readRequiredChar("a"); + readRequiredChar("l"); + readRequiredChar("s"); + readRequiredChar("e"); + return JsonLiteral::FALSE; + } + + void JsonPureStringParser::readRequiredChar(string ch) { + if (!readChar(ch)) { + throw expected("'" + ch + "'"); + } + } + + shared_ptr JsonPureStringParser::readString() { + return make_shared(readStringInternal()); + } + + string JsonPureStringParser::readStringInternal() { + read(); + startCapture(); + while (_current != "\"") { + if (_current == "\\") { + pauseCapture(); + readEscape(); + startCapture(); + } else { + read(); + } + } + string string = endCapture(); + read(); + return string; + } + + void JsonPureStringParser::readEscape() { + read(); + if (_current == "\"" || _current == "/" || _current == "\\") + _captureBuffer += _current; + else if (_current == "b") + _captureBuffer += "\b"; + else if (_current == "f") + _captureBuffer += "\f"; + else if (_current == "n") + _captureBuffer += "\n"; + else if (_current == "r") + _captureBuffer += "\r"; + else if (_current == "t") + _captureBuffer += "\t"; + else + throw expected("valid escape sequence"); + read(); + } + + shared_ptr JsonPureStringParser::readNumber() { + startCapture(); + readChar("-"); + string firstDigit = _current; + if (!readDigit()) { + throw expected("digit"); + } + if (firstDigit != "0") { + while (readDigit()) { } + } + readFraction(); + readExponent(); + return make_shared(endCapture()); + } + + bool JsonPureStringParser::readFraction() { + if (!readChar(".")) { + return false; + } + if (!readDigit()) { + throw expected("digit"); + } + while (readDigit()) { } + return true; + } + + bool JsonPureStringParser::readExponent() { + if (!readChar("e") && !readChar("E")) { + return false; + } + if (!readChar("+")) { + readChar("-"); + } + if (!readDigit()) { + throw expected("digit"); + } + + while (readDigit()) { } + return true; + } + + bool JsonPureStringParser::readChar(string ch) { + if (_current != ch) { + return false; + } + read(); + return true; + } + + bool JsonPureStringParser::readDigit() { + if (!isDigit()) { + return false; + } + read(); + return true; + } + + void JsonPureStringParser::skipWhiteSpace() { + while (isWhiteSpace()) { + read(); + } + } + + void JsonPureStringParser::read() { + if ("\n" == _current) { + _line++; + _column = 0; + } + _index++; + if (_index < _input.length()) { + _current = _input.substr(_index, 1); + } else { + _current = ""; + } + } + + void JsonPureStringParser::startCapture() { + _captureStart = _index; + } + + void JsonPureStringParser::pauseCapture() { + int _end = _current == "" ? _index : _index - 1; + _captureBuffer += _input.substr(_captureStart, _end - _captureStart + 1); + _captureStart = -1; + } + + string JsonPureStringParser::endCapture() { + int _end = _current == "" ? _index : _index - 1; + string captured; + if ("" == _captureBuffer) { + captured = _input.substr(_captureStart, _end - _captureStart + 1); + } else { + _captureBuffer += _input.substr(_captureStart, _end - _captureStart + 1); + captured = _captureBuffer; + _captureBuffer = ""; + } + _captureStart = -1; + return captured; + } + + ParseException JsonPureStringParser::expected(string expected) { + if (isEndOfText()) { + return error("Unexpected end of input"); + } + + return error("Expected " + expected); + } + + ParseException JsonPureStringParser::error(string message) { + return ParseException(message, _index, _line, _column - 1); + } + + bool JsonPureStringParser::isWhiteSpace() { + return " " == _current || "\t" == _current || "\n" == _current || "\r" == _current; + } + + + bool JsonPureStringParser::isDigit() { + return "0" == _current || + "1" == _current || + "2" == _current || + "3" == _current || + "4" == _current || + "5" == _current || + "6" == _current || + "7" == _current || + "8" == _current || + "9" == _current; + } + + bool JsonPureStringParser::isEndOfText() { + return _current == ""; + } + + JsonPureStringParser::JsonPureStringParser(string string) { + _input = string; + _index = -1; + _line = 1; + _captureStart = -1; + _column = 0; + _current = ""; + _captureBuffer = ""; + } + + shared_ptr JsonPureStringParser::parse() { + read(); + skipWhiteSpace(); + shared_ptr result = readValue(); + skipWhiteSpace(); + if (!isEndOfText()) { + throw Error("Unexpected character"); + } + return result; + } + +} diff --git a/benchmarks/C++/src/json/JsonPureStringParser.h b/benchmarks/C++/src/json/JsonPureStringParser.h new file mode 100644 index 00000000..19c36dfd --- /dev/null +++ b/benchmarks/C++/src/json/JsonPureStringParser.h @@ -0,0 +1,64 @@ +#ifndef JSONPURESTRINGPARSER +#define JSONPURESTRINGPARSER + + +#include +#include +#include "../som/Error.cpp" +#include "JsonArray.h" +#include "JsonObject.h" +#include "ParseException.h" +#include "JsonLiteral.h" +#include "JsonNumber.h" +#include "JsonString.h" + +using namespace std; + +namespace json { + class JsonPureStringParser { + private: + string _input; + int _index; + int _line; + int _column; + string _current; + string _captureBuffer; + int _captureStart; + + shared_ptr readValue(); + shared_ptr readObject(); + string readName(); + shared_ptr readArray(); + shared_ptr readNull(); + shared_ptr readTrue(); + shared_ptr readFalse(); + void readRequiredChar(string ch); + shared_ptr readString(); + string readStringInternal(); + void readEscape(); + shared_ptr readNumber(); + bool readFraction(); + bool readExponent(); + bool readChar(string ch); + bool readDigit(); + void skipWhiteSpace(); + void read(); + void startCapture(); + void pauseCapture(); + string endCapture(); + ParseException expected(string expected); + ParseException error(string message); + bool isWhiteSpace(); + bool isDigit(); + bool isEndOfText(); + + public: + JsonPureStringParser(string string); + + shared_ptr parse(); + + }; +} + + +#endif //JSONPURESTRINGPARSER \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonString.cpp b/benchmarks/C++/src/json/JsonString.cpp new file mode 100644 index 00000000..a6eebd1a --- /dev/null +++ b/benchmarks/C++/src/json/JsonString.cpp @@ -0,0 +1,13 @@ +#include "JsonString.h" + + +namespace json { + + JsonString::JsonString(string string) { + _string = string; + } + + bool JsonString::isString() { + return true; + } +} diff --git a/benchmarks/C++/src/json/JsonString.h b/benchmarks/C++/src/json/JsonString.h new file mode 100644 index 00000000..755aa180 --- /dev/null +++ b/benchmarks/C++/src/json/JsonString.h @@ -0,0 +1,21 @@ +#ifndef JSONSTRING +#define JSONSTRING + +#include +#include "JsonValue.h" + +using namespace std; + +namespace json { + class JsonString : public JsonValue { + private: + string _string; + public: + + JsonString(string string); + + bool isString() override; + }; +} + +#endif //JSONSTRING \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonValue.cpp b/benchmarks/C++/src/json/JsonValue.cpp new file mode 100644 index 00000000..e7bf5e2e --- /dev/null +++ b/benchmarks/C++/src/json/JsonValue.cpp @@ -0,0 +1,55 @@ +#include "JsonValue.h" + +namespace json { + + bool JsonValue::isObject() { + return false; + } + + + bool JsonValue::isArray() { + return false; + } + + + bool JsonValue::isNumber() { + return false; + } + + + bool JsonValue::isString() { + return false; + } + + + bool JsonValue::isBoolean() { + return false; + } + + + bool JsonValue::isTrue() { + return false; + } + + + bool JsonValue::isFalse() { + return false; + } + + + bool JsonValue::isNull() { + return false; + } + + shared_ptr JsonValue::asObject() { + throw Error("Not an object: " + toString()); + } + + shared_ptr JsonValue::asArray() { + throw Error("Not an array: " + toString()); + } + + string JsonValue::toString() { + return ""; + } +} diff --git a/benchmarks/C++/src/json/JsonValue.h b/benchmarks/C++/src/json/JsonValue.h new file mode 100644 index 00000000..8e6c617f --- /dev/null +++ b/benchmarks/C++/src/json/JsonValue.h @@ -0,0 +1,32 @@ +#ifndef JSONVALUE +#define JSONVALUE + +#include +#include "../som/Error.cpp" + +using namespace std; + +namespace json { + + class JsonArray; + class JsonObject; + + class JsonValue { + public: + JsonValue() = default; + + virtual bool isObject(); + virtual bool isArray(); + virtual bool isNumber(); + virtual bool isString(); + virtual bool isBoolean(); + virtual bool isTrue(); + virtual bool isFalse(); + virtual bool isNull(); + virtual shared_ptr asObject(); + virtual shared_ptr asArray(); + virtual string toString(); + }; +} + +#endif //JSONVALUE \ No newline at end of file diff --git a/benchmarks/C++/src/json/ParseException.cpp b/benchmarks/C++/src/json/ParseException.cpp new file mode 100644 index 00000000..d943af54 --- /dev/null +++ b/benchmarks/C++/src/json/ParseException.cpp @@ -0,0 +1,27 @@ +#include "ParseException.h" + +namespace json { + ParseException::ParseException(string message, int offset, int line, int column) { + _offset = offset; + _line = line; + _column = column; + _what = message + " at " + to_string(line) + ":" + to_string(column); + } + + int ParseException::getOffset() { + return _offset; + } + + int ParseException::getLine() { + return _line; + } + + int ParseException::getColumn() { + return _column; + } + + const char *ParseException::what() const throw() { + return (_what.c_str()); + } + +} \ No newline at end of file diff --git a/benchmarks/C++/src/json/ParseException.h b/benchmarks/C++/src/json/ParseException.h new file mode 100644 index 00000000..7fc2b83c --- /dev/null +++ b/benchmarks/C++/src/json/ParseException.h @@ -0,0 +1,26 @@ +#ifndef PARSEEXCEPTION +#define PARSEEXCEPTION + +#include + +using namespace std; + +namespace json { + class ParseException : virtual public exception { + private: + int _offset; + int _line; + int _column; + string _what; + + public: + ParseException(string message, int offset, int line, int column); + + int getOffset(); + int getLine(); + int getColumn(); + const char *what() const throw(); + }; +} + +#endif //PARSEEXCEPTION \ No newline at end of file From 7e88468e61a65912ea7a47694bf5078db5083082 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sat, 6 Jan 2024 18:11:12 +0000 Subject: [PATCH 11/40] [C++] Modernize Json - use normally allocated instances for null, true, false literals to avoid making the memory management more complex. Signed-off-by: Stefan Marr --- benchmarks/C++/src/Json.cpp | 27 - benchmarks/C++/src/Json.h | 18 - benchmarks/C++/src/json.h | 993 ++++++++++++++++++ benchmarks/C++/src/json/JsonArray.cpp | 30 - benchmarks/C++/src/json/JsonArray.h | 26 - benchmarks/C++/src/json/JsonLiteral.cpp | 42 - benchmarks/C++/src/json/JsonLiteral.h | 29 - benchmarks/C++/src/json/JsonNumber.cpp | 20 - benchmarks/C++/src/json/JsonNumber.h | 23 - benchmarks/C++/src/json/JsonObject.cpp | 53 - benchmarks/C++/src/json/JsonObject.h | 34 - .../C++/src/json/JsonPureStringParser.cpp | 305 ------ .../C++/src/json/JsonPureStringParser.h | 64 -- benchmarks/C++/src/json/JsonString.cpp | 13 - benchmarks/C++/src/json/JsonString.h | 21 - benchmarks/C++/src/json/JsonValue.cpp | 55 - benchmarks/C++/src/json/JsonValue.h | 32 - benchmarks/C++/src/json/ParseException.cpp | 27 - benchmarks/C++/src/json/ParseException.h | 26 - benchmarks/C++/src/run.h | 4 + benchmarks/C++/src/som/vector.h | 6 + 21 files changed, 1003 insertions(+), 845 deletions(-) delete mode 100644 benchmarks/C++/src/Json.cpp delete mode 100644 benchmarks/C++/src/Json.h create mode 100644 benchmarks/C++/src/json.h delete mode 100644 benchmarks/C++/src/json/JsonArray.cpp delete mode 100644 benchmarks/C++/src/json/JsonArray.h delete mode 100644 benchmarks/C++/src/json/JsonLiteral.cpp delete mode 100644 benchmarks/C++/src/json/JsonLiteral.h delete mode 100644 benchmarks/C++/src/json/JsonNumber.cpp delete mode 100644 benchmarks/C++/src/json/JsonNumber.h delete mode 100644 benchmarks/C++/src/json/JsonObject.cpp delete mode 100644 benchmarks/C++/src/json/JsonObject.h delete mode 100644 benchmarks/C++/src/json/JsonPureStringParser.cpp delete mode 100644 benchmarks/C++/src/json/JsonPureStringParser.h delete mode 100644 benchmarks/C++/src/json/JsonString.cpp delete mode 100644 benchmarks/C++/src/json/JsonString.h delete mode 100644 benchmarks/C++/src/json/JsonValue.cpp delete mode 100644 benchmarks/C++/src/json/JsonValue.h delete mode 100644 benchmarks/C++/src/json/ParseException.cpp delete mode 100644 benchmarks/C++/src/json/ParseException.h diff --git a/benchmarks/C++/src/Json.cpp b/benchmarks/C++/src/Json.cpp deleted file mode 100644 index 6aaa6598..00000000 --- a/benchmarks/C++/src/Json.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "Json.h" - -using namespace std; - -namespace json { - - any Json::benchmark() { - return (make_shared(rapBenchmarkMinified))->parse(); - } - - bool Json::verifyResult(any r) { - shared_ptr result = any_cast>(r); - if (!result->isObject()) { - return false; - } - shared_ptr resultObject = result->asObject(); - if (!resultObject->get("head")->isObject()) { - return false; - } - if (!resultObject->get("operations")->isArray()) { - return false; - } - shared_ptr resultArray = resultObject->get("operations")->asArray(); - return resultArray->size() == 156; - } - -} \ No newline at end of file diff --git a/benchmarks/C++/src/Json.h b/benchmarks/C++/src/Json.h deleted file mode 100644 index 61a6fa85..00000000 --- a/benchmarks/C++/src/Json.h +++ /dev/null @@ -1,18 +0,0 @@ -#include "Benchmark.h" -#include "json/JsonPureStringParser.h" -#include - -using namespace std; - -namespace json { - class Json : public Benchmark { - private: - string rapBenchmarkMinified = "{\"head\":{\"requestCounter\":4},\"operations\":[[\"destroy\",\"w54\"],[\"set\",\"w2\",{\"activeControl\":\"w99\"}],[\"set\",\"w21\",{\"customVariant\":\"variant_navigation\"}],[\"set\",\"w28\",{\"customVariant\":\"variant_selected\"}],[\"set\",\"w53\",{\"children\":[\"w95\"]}],[\"create\",\"w95\",\"rwt.widgets.Composite\",{\"parent\":\"w53\",\"style\":[\"NONE\"],\"bounds\":[0,0,1008,586],\"children\":[\"w96\",\"w97\"],\"tabIndex\":-1,\"clientArea\":[0,0,1008,586]}],[\"create\",\"w96\",\"rwt.widgets.Label\",{\"parent\":\"w95\",\"style\":[\"NONE\"],\"bounds\":[10,30,112,26],\"tabIndex\":-1,\"customVariant\":\"variant_pageHeadline\",\"text\":\"TableViewer\"}],[\"create\",\"w97\",\"rwt.widgets.Composite\",{\"parent\":\"w95\",\"style\":[\"NONE\"],\"bounds\":[0,61,1008,525],\"children\":[\"w98\",\"w99\",\"w226\",\"w228\"],\"tabIndex\":-1,\"clientArea\":[0,0,1008,525]}],[\"create\",\"w98\",\"rwt.widgets.Text\",{\"parent\":\"w97\",\"style\":[\"LEFT\",\"SINGLE\",\"BORDER\"],\"bounds\":[10,10,988,32],\"tabIndex\":22,\"activeKeys\":[\"#13\",\"#27\",\"#40\"]}],[\"listen\",\"w98\",{\"KeyDown\":true,\"Modify\":true}],[\"create\",\"w99\",\"rwt.widgets.Grid\",{\"parent\":\"w97\",\"style\":[\"SINGLE\",\"BORDER\"],\"appearance\":\"table\",\"indentionWidth\":0,\"treeColumn\":-1,\"markupEnabled\":false}],[\"create\",\"w100\",\"rwt.widgets.ScrollBar\",{\"parent\":\"w99\",\"style\":[\"HORIZONTAL\"]}],[\"create\",\"w101\",\"rwt.widgets.ScrollBar\",{\"parent\":\"w99\",\"style\":[\"VERTICAL\"]}],[\"set\",\"w99\",{\"bounds\":[10,52,988,402],\"children\":[],\"tabIndex\":23,\"activeKeys\":[\"CTRL+#70\",\"CTRL+#78\",\"CTRL+#82\",\"CTRL+#89\",\"CTRL+#83\",\"CTRL+#71\",\"CTRL+#69\"],\"cancelKeys\":[\"CTRL+#70\",\"CTRL+#78\",\"CTRL+#82\",\"CTRL+#89\",\"CTRL+#83\",\"CTRL+#71\",\"CTRL+#69\"]}],[\"listen\",\"w99\",{\"MouseDown\":true,\"MouseUp\":true,\"MouseDoubleClick\":true,\"KeyDown\":true}],[\"set\",\"w99\",{\"itemCount\":118,\"itemHeight\":28,\"itemMetrics\":[[0,0,50,3,0,3,44],[1,50,50,53,0,53,44],[2,100,140,103,0,103,134],[3,240,180,243,0,243,174],[4,420,50,423,0,423,44],[5,470,50,473,0,473,44]],\"columnCount\":6,\"headerHeight\":35,\"headerVisible\":true,\"linesVisible\":true,\"focusItem\":\"w108\",\"selection\":[\"w108\"]}],[\"listen\",\"w99\",{\"Selection\":true,\"DefaultSelection\":true}],[\"set\",\"w99\",{\"enableCellToolTip\":true}],[\"listen\",\"w100\",{\"Selection\":true}],[\"set\",\"w101\",{\"visibility\":true}],[\"listen\",\"w101\",{\"Selection\":true}],[\"create\",\"w102\",\"rwt.widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Nr.\",\"width\":50,\"moveable\":true}],[\"listen\",\"w102\",{\"Selection\":true}],[\"create\",\"w103\",\"rwt.widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Sym.\",\"index\":1,\"left\":50,\"width\":50,\"moveable\":true}],[\"listen\",\"w103\",{\"Selection\":true}],[\"create\",\"w104\",\"rwt.widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Name\",\"index\":2,\"left\":100,\"width\":140,\"moveable\":true}],[\"listen\",\"w104\",{\"Selection\":true}],[\"create\",\"w105\",\"rwt.widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Series\",\"index\":3,\"left\":240,\"width\":180,\"moveable\":true}],[\"listen\",\"w105\",{\"Selection\":true}],[\"create\",\"w106\",\"rwt.widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Group\",\"index\":4,\"left\":420,\"width\":50,\"moveable\":true}],[\"listen\",\"w106\",{\"Selection\":true}],[\"create\",\"w107\",\"rwt.widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Period\",\"index\":5,\"left\":470,\"width\":50,\"moveable\":true}],[\"listen\",\"w107\",{\"Selection\":true}],[\"create\",\"w108\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":0,\"texts\":[\"1\",\"H\",\"Hydrogen\",\"Nonmetal\",\"1\",\"1\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w109\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":1,\"texts\":[\"2\",\"He\",\"Helium\",\"Noble gas\",\"18\",\"1\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w110\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":2,\"texts\":[\"3\",\"Li\",\"Lithium\",\"Alkali metal\",\"1\",\"2\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255],null,null]}],[\"create\",\"w111\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":3,\"texts\":[\"4\",\"Be\",\"Beryllium\",\"Alkaline earth metal\",\"2\",\"2\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255],null,null]}],[\"create\",\"w112\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":4,\"texts\":[\"5\",\"B\",\"Boron\",\"Metalloid\",\"13\",\"2\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w113\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":5,\"texts\":[\"6\",\"C\",\"Carbon\",\"Nonmetal\",\"14\",\"2\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w114\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":6,\"texts\":[\"7\",\"N\",\"Nitrogen\",\"Nonmetal\",\"15\",\"2\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w115\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":7,\"texts\":[\"8\",\"O\",\"Oxygen\",\"Nonmetal\",\"16\",\"2\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w116\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":8,\"texts\":[\"9\",\"F\",\"Fluorine\",\"Halogen\",\"17\",\"2\"],\"cellBackgrounds\":[null,null,null,[252,233,79,255],null,null]}],[\"create\",\"w117\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":9,\"texts\":[\"10\",\"Ne\",\"Neon\",\"Noble gas\",\"18\",\"2\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w118\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":10,\"texts\":[\"11\",\"Na\",\"Sodium\",\"Alkali metal\",\"1\",\"3\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255],null,null]}],[\"create\",\"w119\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":11,\"texts\":[\"12\",\"Mg\",\"Magnesium\",\"Alkaline earth metal\",\"2\",\"3\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255],null,null]}],[\"create\",\"w120\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":12,\"texts\":[\"13\",\"Al\",\"Aluminium\",\"Poor metal\",\"13\",\"3\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w121\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":13,\"texts\":[\"14\",\"Si\",\"Silicon\",\"Metalloid\",\"14\",\"3\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w122\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":14,\"texts\":[\"15\",\"P\",\"Phosphorus\",\"Nonmetal\",\"15\",\"3\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w123\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":15,\"texts\":[\"16\",\"S\",\"Sulfur\",\"Nonmetal\",\"16\",\"3\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w124\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":16,\"texts\":[\"17\",\"Cl\",\"Chlorine\",\"Halogen\",\"17\",\"3\"],\"cellBackgrounds\":[null,null,null,[252,233,79,255],null,null]}],[\"create\",\"w125\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":17,\"texts\":[\"18\",\"Ar\",\"Argon\",\"Noble gas\",\"18\",\"3\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w126\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":18,\"texts\":[\"19\",\"K\",\"Potassium\",\"Alkali metal\",\"1\",\"4\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255],null,null]}],[\"create\",\"w127\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":19,\"texts\":[\"20\",\"Ca\",\"Calcium\",\"Alkaline earth metal\",\"2\",\"4\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255],null,null]}],[\"create\",\"w128\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":20,\"texts\":[\"21\",\"Sc\",\"Scandium\",\"Transition metal\",\"3\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w129\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":21,\"texts\":[\"22\",\"Ti\",\"Titanium\",\"Transition metal\",\"4\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w130\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":22,\"texts\":[\"23\",\"V\",\"Vanadium\",\"Transition metal\",\"5\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w131\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":23,\"texts\":[\"24\",\"Cr\",\"Chromium\",\"Transition metal\",\"6\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w132\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":24,\"texts\":[\"25\",\"Mn\",\"Manganese\",\"Transition metal\",\"7\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w133\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":25,\"texts\":[\"26\",\"Fe\",\"Iron\",\"Transition metal\",\"8\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w134\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":26,\"texts\":[\"27\",\"Co\",\"Cobalt\",\"Transition metal\",\"9\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w135\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":27,\"texts\":[\"28\",\"Ni\",\"Nickel\",\"Transition metal\",\"10\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w136\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":28,\"texts\":[\"29\",\"Cu\",\"Copper\",\"Transition metal\",\"11\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w137\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":29,\"texts\":[\"30\",\"Zn\",\"Zinc\",\"Transition metal\",\"12\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w138\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":30,\"texts\":[\"31\",\"Ga\",\"Gallium\",\"Poor metal\",\"13\",\"4\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w139\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":31,\"texts\":[\"32\",\"Ge\",\"Germanium\",\"Metalloid\",\"14\",\"4\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w140\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":32,\"texts\":[\"33\",\"As\",\"Arsenic\",\"Metalloid\",\"15\",\"4\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w141\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":33,\"texts\":[\"34\",\"Se\",\"Selenium\",\"Nonmetal\",\"16\",\"4\"],\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[\"create\",\"w142\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":34,\"texts\":[\"35\",\"Br\",\"Bromine\",\"Halogen\",\"17\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,233,79,255],null,null]}],[\"create\",\"w143\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":35,\"texts\":[\"36\",\"Kr\",\"Krypton\",\"Noble gas\",\"18\",\"4\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w144\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":36,\"texts\":[\"37\",\"Rb\",\"Rubidium\",\"Alkali metal\",\"1\",\"5\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255],null,null]}],[\"create\",\"w145\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":37,\"texts\":[\"38\",\"Sr\",\"Strontium\",\"Alkaline earth metal\",\"2\",\"5\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255],null,null]}],[\"create\",\"w146\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":38,\"texts\":[\"39\",\"Y\",\"Yttrium\",\"Transition metal\",\"3\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w147\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":39,\"texts\":[\"40\",\"Zr\",\"Zirconium\",\"Transition metal\",\"4\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w148\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":40,\"texts\":[\"41\",\"Nb\",\"Niobium\",\"Transition metal\",\"5\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w149\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":41,\"texts\":[\"42\",\"Mo\",\"Molybdenum\",\"Transition metal\",\"6\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w150\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":42,\"texts\":[\"43\",\"Tc\",\"Technetium\",\"Transition metal\",\"7\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w151\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":43,\"texts\":[\"44\",\"Ru\",\"Ruthenium\",\"Transition metal\",\"8\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w152\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":44,\"texts\":[\"45\",\"Rh\",\"Rhodium\",\"Transition metal\",\"9\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w153\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":45,\"texts\":[\"46\",\"Pd\",\"Palladium\",\"Transition metal\",\"10\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w154\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":46,\"texts\":[\"47\",\"Ag\",\"Silver\",\"Transition metal\",\"11\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w155\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":47,\"texts\":[\"48\",\"Cd\",\"Cadmium\",\"Transition metal\",\"12\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w156\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":48,\"texts\":[\"49\",\"In\",\"Indium\",\"Poor metal\",\"13\",\"5\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w157\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":49,\"texts\":[\"50\",\"Sn\",\"Tin\",\"Poor metal\",\"14\",\"5\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w158\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":50,\"texts\":[\"51\",\"Sb\",\"Antimony\",\"Metalloid\",\"15\",\"5\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w159\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":51,\"texts\":[\"52\",\"Te\",\"Tellurium\",\"Metalloid\",\"16\",\"5\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w160\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":52,\"texts\":[\"53\",\"I\",\"Iodine\",\"Halogen\",\"17\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,233,79,255],null,null]}],[\"create\",\"w161\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":53,\"texts\":[\"54\",\"Xe\",\"Xenon\",\"Noble gas\",\"18\",\"5\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w162\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":54,\"texts\":[\"55\",\"Cs\",\"Caesium\",\"Alkali metal\",\"1\",\"6\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255],null,null]}],[\"create\",\"w163\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":55,\"texts\":[\"56\",\"Ba\",\"Barium\",\"Alkaline earth metal\",\"2\",\"6\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255],null,null]}],[\"create\",\"w164\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":56,\"texts\":[\"57\",\"La\",\"Lanthanum\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w165\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":57,\"texts\":[\"58\",\"Ce\",\"Cerium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w166\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":58,\"texts\":[\"59\",\"Pr\",\"Praseodymium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w167\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":59,\"texts\":[\"60\",\"Nd\",\"Neodymium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w168\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":60,\"texts\":[\"61\",\"Pm\",\"Promethium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w169\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":61,\"texts\":[\"62\",\"Sm\",\"Samarium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w170\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":62,\"texts\":[\"63\",\"Eu\",\"Europium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w171\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":63,\"texts\":[\"64\",\"Gd\",\"Gadolinium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w172\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":64,\"texts\":[\"65\",\"Tb\",\"Terbium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w173\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":65,\"texts\":[\"66\",\"Dy\",\"Dysprosium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w174\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":66,\"texts\":[\"67\",\"Ho\",\"Holmium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w175\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":67,\"texts\":[\"68\",\"Er\",\"Erbium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w176\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":68,\"texts\":[\"69\",\"Tm\",\"Thulium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w177\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":69,\"texts\":[\"70\",\"Yb\",\"Ytterbium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w178\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":70,\"texts\":[\"71\",\"Lu\",\"Lutetium\",\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w179\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":71,\"texts\":[\"72\",\"Hf\",\"Hafnium\",\"Transition metal\",\"4\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w180\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":72,\"texts\":[\"73\",\"Ta\",\"Tantalum\",\"Transition metal\",\"5\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w181\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":73,\"texts\":[\"74\",\"W\",\"Tungsten\",\"Transition metal\",\"6\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w182\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":74,\"texts\":[\"75\",\"Re\",\"Rhenium\",\"Transition metal\",\"7\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w183\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":75,\"texts\":[\"76\",\"Os\",\"Osmium\",\"Transition metal\",\"8\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w184\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":76,\"texts\":[\"77\",\"Ir\",\"Iridium\",\"Transition metal\",\"9\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w185\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":77,\"texts\":[\"78\",\"Pt\",\"Platinum\",\"Transition metal\",\"10\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w186\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":78,\"texts\":[\"79\",\"Au\",\"Gold\",\"Transition metal\",\"11\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w187\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":79,\"texts\":[\"80\",\"Hg\",\"Mercury\",\"Transition metal\",\"12\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w188\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":80,\"texts\":[\"81\",\"Tl\",\"Thallium\",\"Poor metal\",\"13\",\"6\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w189\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":81,\"texts\":[\"82\",\"Pb\",\"Lead\",\"Poor metal\",\"14\",\"6\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w190\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":82,\"texts\":[\"83\",\"Bi\",\"Bismuth\",\"Poor metal\",\"15\",\"6\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w191\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":83,\"texts\":[\"84\",\"Po\",\"Polonium\",\"Metalloid\",\"16\",\"6\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}],[\"create\",\"w192\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":84,\"texts\":[\"85\",\"At\",\"Astatine\",\"Halogen\",\"17\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,233,79,255],null,null]}],[\"create\",\"w193\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":85,\"texts\":[\"86\",\"Rn\",\"Radon\",\"Noble gas\",\"18\",\"6\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w194\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":86,\"texts\":[\"87\",\"Fr\",\"Francium\",\"Alkali metal\",\"1\",\"7\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255],null,null]}],[\"create\",\"w195\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":87,\"texts\":[\"88\",\"Ra\",\"Radium\",\"Alkaline earth metal\",\"2\",\"7\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255],null,null]}],[\"create\",\"w196\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":88,\"texts\":[\"89\",\"Ac\",\"Actinium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w197\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":89,\"texts\":[\"90\",\"Th\",\"Thorium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w198\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":90,\"texts\":[\"91\",\"Pa\",\"Protactinium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w199\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":91,\"texts\":[\"92\",\"U\",\"Uranium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w200\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":92,\"texts\":[\"93\",\"Np\",\"Neptunium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w201\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":93,\"texts\":[\"94\",\"Pu\",\"Plutonium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w202\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":94,\"texts\":[\"95\",\"Am\",\"Americium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w203\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":95,\"texts\":[\"96\",\"Cm\",\"Curium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w204\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":96,\"texts\":[\"97\",\"Bk\",\"Berkelium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w205\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":97,\"texts\":[\"98\",\"Cf\",\"Californium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w206\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":98,\"texts\":[\"99\",\"Es\",\"Einsteinium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w207\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":99,\"texts\":[\"100\",\"Fm\",\"Fermium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w208\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":100,\"texts\":[\"101\",\"Md\",\"Mendelevium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w209\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":101,\"texts\":[\"102\",\"No\",\"Nobelium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w210\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":102,\"texts\":[\"103\",\"Lr\",\"Lawrencium\",\"Actinide\",\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[\"create\",\"w211\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":103,\"texts\":[\"104\",\"Rf\",\"Rutherfordium\",\"Transition metal\",\"4\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w212\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":104,\"texts\":[\"105\",\"Db\",\"Dubnium\",\"Transition metal\",\"5\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w213\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":105,\"texts\":[\"106\",\"Sg\",\"Seaborgium\",\"Transition metal\",\"6\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w214\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":106,\"texts\":[\"107\",\"Bh\",\"Bohrium\",\"Transition metal\",\"7\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w215\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":107,\"texts\":[\"108\",\"Hs\",\"Hassium\",\"Transition metal\",\"8\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w216\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":108,\"texts\":[\"109\",\"Mt\",\"Meitnerium\",\"Transition metal\",\"9\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w217\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":109,\"texts\":[\"110\",\"Ds\",\"Darmstadtium\",\"Transition metal\",\"10\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w218\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":110,\"texts\":[\"111\",\"Rg\",\"Roentgenium\",\"Transition metal\",\"11\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w219\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":111,\"texts\":[\"112\",\"Uub\",\"Ununbium\",\"Transition metal\",\"12\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255],null,null]}],[\"create\",\"w220\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":112,\"texts\":[\"113\",\"Uut\",\"Ununtrium\",\"Poor metal\",\"13\",\"7\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w221\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":113,\"texts\":[\"114\",\"Uuq\",\"Ununquadium\",\"Poor metal\",\"14\",\"7\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w222\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":114,\"texts\":[\"115\",\"Uup\",\"Ununpentium\",\"Poor metal\",\"15\",\"7\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w223\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":115,\"texts\":[\"116\",\"Uuh\",\"Ununhexium\",\"Poor metal\",\"16\",\"7\"],\"cellBackgrounds\":[null,null,null,[238,238,236,255],null,null]}],[\"create\",\"w224\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":116,\"texts\":[\"117\",\"Uus\",\"Ununseptium\",\"Halogen\",\"17\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,233,79,255],null,null]}],[\"create\",\"w225\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\",\"index\":117,\"texts\":[\"118\",\"Uuo\",\"Ununoctium\",\"Noble gas\",\"18\",\"7\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255],null,null]}],[\"create\",\"w226\",\"rwt.widgets.Composite\",{\"parent\":\"w97\",\"style\":[\"BORDER\"],\"bounds\":[10,464,988,25],\"children\":[\"w227\"],\"tabIndex\":-1,\"clientArea\":[0,0,986,23]}],[\"create\",\"w227\",\"rwt.widgets.Label\",{\"parent\":\"w226\",\"style\":[\"NONE\"],\"bounds\":[10,10,966,3],\"tabIndex\":-1,\"text\":\"Hydrogen (H)\"}],[\"create\",\"w228\",\"rwt.widgets.Label\",{\"parent\":\"w97\",\"style\":[\"WRAP\"],\"bounds\":[10,499,988,16],\"tabIndex\":-1,\"foreground\":[150,150,150,255],\"font\":[[\"Verdana\",\"Lucida Sans\",\"Arial\",\"Helvetica\",\"sans-serif\"],10,false,false],\"text\":\"Shortcuts: [CTRL+F] - Filter | Sort by: [CTRL+R] - Number, [CTRL+Y] - Symbol, [CTRL+N] - Name, [CTRL+S] - Series, [CTRL+G] - Group, [CTRL+E] - Period\"}],[\"set\",\"w1\",{\"focusControl\":\"w99\"}],[\"call\",\"rwt.client.BrowserNavigation\",\"addToHistory\",{\"entries\":[[\"tableviewer\",\"TableViewer\"]]}]]}"; - - - public: - any benchmark() override; - bool verifyResult(any r) override; - - }; -} \ No newline at end of file diff --git a/benchmarks/C++/src/json.h b/benchmarks/C++/src/json.h new file mode 100644 index 00000000..f05d5658 --- /dev/null +++ b/benchmarks/C++/src/json.h @@ -0,0 +1,993 @@ +#pragma once + +#include + +#include "benchmark.h" +#include "som/error.h" +#include "som/vector.h" + +using std::string; + +const string rapBenchmarkMinified = + "{\"head\":{\"requestCounter\":4},\"operations\":[[\"destroy\",\"w54\"],[" + "\"set\",\"w2\",{\"activeControl\":\"w99\"}],[\"set\",\"w21\",{" + "\"customVariant\":\"variant_navigation\"}],[\"set\",\"w28\",{" + "\"customVariant\":\"variant_selected\"}],[\"set\",\"w53\",{\"children\":[" + "\"w95\"]}],[\"create\",\"w95\",\"rwt.widgets.Composite\",{\"parent\":" + "\"w53\",\"style\":[\"NONE\"],\"bounds\":[0,0,1008,586],\"children\":[" + "\"w96\",\"w97\"],\"tabIndex\":-1,\"clientArea\":[0,0,1008,586]}],[" + "\"create\",\"w96\",\"rwt.widgets.Label\",{\"parent\":\"w95\",\"style\":[" + "\"NONE\"],\"bounds\":[10,30,112,26],\"tabIndex\":-1,\"customVariant\":" + "\"variant_pageHeadline\",\"text\":\"TableViewer\"}],[\"create\",\"w97\"," + "\"rwt.widgets.Composite\",{\"parent\":\"w95\",\"style\":[\"NONE\"]," + "\"bounds\":[0,61,1008,525],\"children\":[\"w98\",\"w99\",\"w226\"," + "\"w228\"],\"tabIndex\":-1,\"clientArea\":[0,0,1008,525]}],[\"create\"," + "\"w98\",\"rwt.widgets.Text\",{\"parent\":\"w97\",\"style\":[\"LEFT\"," + "\"SINGLE\",\"BORDER\"],\"bounds\":[10,10,988,32],\"tabIndex\":22," + "\"activeKeys\":[\"#13\",\"#27\",\"#40\"]}],[\"listen\",\"w98\",{" + "\"KeyDown\":true,\"Modify\":true}],[\"create\",\"w99\",\"rwt.widgets." + "Grid\",{\"parent\":\"w97\",\"style\":[\"SINGLE\",\"BORDER\"]," + "\"appearance\":\"table\",\"indentionWidth\":0,\"treeColumn\":-1," + "\"markupEnabled\":false}],[\"create\",\"w100\",\"rwt.widgets.ScrollBar\",{" + "\"parent\":\"w99\",\"style\":[\"HORIZONTAL\"]}],[\"create\",\"w101\"," + "\"rwt.widgets.ScrollBar\",{\"parent\":\"w99\",\"style\":[\"VERTICAL\"]}],[" + "\"set\",\"w99\",{\"bounds\":[10,52,988,402],\"children\":[],\"tabIndex\":" + "23,\"activeKeys\":[\"CTRL+#70\",\"CTRL+#78\",\"CTRL+#82\",\"CTRL+#89\"," + "\"CTRL+#83\",\"CTRL+#71\",\"CTRL+#69\"],\"cancelKeys\":[\"CTRL+#70\"," + "\"CTRL+#78\",\"CTRL+#82\",\"CTRL+#89\",\"CTRL+#83\",\"CTRL+#71\",\"CTRL+#" + "69\"]}],[\"listen\",\"w99\",{\"MouseDown\":true,\"MouseUp\":true," + "\"MouseDoubleClick\":true,\"KeyDown\":true}],[\"set\",\"w99\",{" + "\"itemCount\":118,\"itemHeight\":28,\"itemMetrics\":[[0,0,50,3,0,3,44],[1," + "50,50,53,0,53,44],[2,100,140,103,0,103,134],[3,240,180,243,0,243,174],[4," + "420,50,423,0,423,44],[5,470,50,473,0,473,44]],\"columnCount\":6," + "\"headerHeight\":35,\"headerVisible\":true,\"linesVisible\":true," + "\"focusItem\":\"w108\",\"selection\":[\"w108\"]}],[\"listen\",\"w99\",{" + "\"Selection\":true,\"DefaultSelection\":true}],[\"set\",\"w99\",{" + "\"enableCellToolTip\":true}],[\"listen\",\"w100\",{\"Selection\":true}],[" + "\"set\",\"w101\",{\"visibility\":true}],[\"listen\",\"w101\",{" + "\"Selection\":true}],[\"create\",\"w102\",\"rwt.widgets.GridColumn\",{" + "\"parent\":\"w99\",\"text\":\"Nr.\",\"width\":50,\"moveable\":true}],[" + "\"listen\",\"w102\",{\"Selection\":true}],[\"create\",\"w103\",\"rwt." + "widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Sym.\",\"index\":1," + "\"left\":50,\"width\":50,\"moveable\":true}],[\"listen\",\"w103\",{" + "\"Selection\":true}],[\"create\",\"w104\",\"rwt.widgets.GridColumn\",{" + "\"parent\":\"w99\",\"text\":\"Name\",\"index\":2,\"left\":100,\"width\":" + "140,\"moveable\":true}],[\"listen\",\"w104\",{\"Selection\":true}],[" + "\"create\",\"w105\",\"rwt.widgets.GridColumn\",{\"parent\":\"w99\"," + "\"text\":\"Series\",\"index\":3,\"left\":240,\"width\":180,\"moveable\":" + "true}],[\"listen\",\"w105\",{\"Selection\":true}],[\"create\",\"w106\"," + "\"rwt.widgets.GridColumn\",{\"parent\":\"w99\",\"text\":\"Group\"," + "\"index\":4,\"left\":420,\"width\":50,\"moveable\":true}],[\"listen\"," + "\"w106\",{\"Selection\":true}],[\"create\",\"w107\",\"rwt.widgets." + "GridColumn\",{\"parent\":\"w99\",\"text\":\"Period\",\"index\":5,\"left\":" + "470,\"width\":50,\"moveable\":true}],[\"listen\",\"w107\",{\"Selection\":" + "true}],[\"create\",\"w108\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":0,\"texts\":[\"1\",\"H\",\"Hydrogen\",\"Nonmetal\",\"1\",\"1\"]," + "\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[" + "\"create\",\"w109\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":1,\"texts\":[\"2\",\"He\",\"Helium\",\"Noble " + "gas\",\"18\",\"1\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255]," + "null,null]}],[\"create\",\"w110\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":2,\"texts\":[\"3\",\"Li\",\"Lithium\",\"Alkali " + "metal\",\"1\",\"2\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255]," + "null,null]}],[\"create\",\"w111\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":3,\"texts\":[\"4\",\"Be\",\"Beryllium\",\"Alkaline " + "earth " + "metal\",\"2\",\"2\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255]" + ",null,null]}],[\"create\",\"w112\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":4,\"texts\":[\"5\",\"B\",\"Boron\",\"Metalloid\",\"13\"," + "\"2\"],\"cellBackgrounds\":[null,null,null,[156,159,153,255],null,null]}]," + "[\"create\",\"w113\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":5,\"texts\":[\"6\",\"C\",\"Carbon\",\"Nonmetal\",\"14\",\"2\"]," + "\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[" + "\"create\",\"w114\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":6,\"texts\":[\"7\",\"N\",\"Nitrogen\",\"Nonmetal\",\"15\",\"2\"]" + ",\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[" + "\"create\",\"w115\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":7,\"texts\":[\"8\",\"O\",\"Oxygen\",\"Nonmetal\",\"16\",\"2\"]," + "\"cellBackgrounds\":[null,null,null,[138,226,52,255],null,null]}],[" + "\"create\",\"w116\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":8,\"texts\":[\"9\",\"F\",\"Fluorine\",\"Halogen\",\"17\",\"2\"]," + "\"cellBackgrounds\":[null,null,null,[252,233,79,255],null,null]}],[" + "\"create\",\"w117\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":9,\"texts\":[\"10\",\"Ne\",\"Neon\",\"Noble " + "gas\",\"18\",\"2\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255]," + "null,null]}],[\"create\",\"w118\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":10,\"texts\":[\"11\",\"Na\",\"Sodium\",\"Alkali " + "metal\",\"1\",\"3\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255]," + "null,null]}],[\"create\",\"w119\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":11,\"texts\":[\"12\",\"Mg\",\"Magnesium\",\"Alkaline " + "earth " + "metal\",\"2\",\"3\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255]" + ",null,null]}],[\"create\",\"w120\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":12,\"texts\":[\"13\",\"Al\",\"Aluminium\",\"Poor " + "metal\",\"13\",\"3\"],\"cellBackgrounds\":[null,null,null,[238,238,236," + "255],null,null]}],[\"create\",\"w121\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":13,\"texts\":[\"14\",\"Si\",\"Silicon\"," + "\"Metalloid\",\"14\",\"3\"],\"cellBackgrounds\":[null,null,null,[156,159," + "153,255],null,null]}],[\"create\",\"w122\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":14,\"texts\":[\"15\",\"P\",\"Phosphorus\"," + "\"Nonmetal\",\"15\",\"3\"],\"cellBackgrounds\":[null,null,null,[138,226," + "52,255],null,null]}],[\"create\",\"w123\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":15,\"texts\":[\"16\",\"S\",\"Sulfur\"," + "\"Nonmetal\",\"16\",\"3\"],\"cellBackgrounds\":[null,null,null,[138,226," + "52,255],null,null]}],[\"create\",\"w124\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":16,\"texts\":[\"17\",\"Cl\",\"Chlorine\"," + "\"Halogen\",\"17\",\"3\"],\"cellBackgrounds\":[null,null,null,[252,233,79," + "255],null,null]}],[\"create\",\"w125\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":17,\"texts\":[\"18\",\"Ar\",\"Argon\"," + "\"Noble " + "gas\",\"18\",\"3\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255]," + "null,null]}],[\"create\",\"w126\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":18,\"texts\":[\"19\",\"K\",\"Potassium\",\"Alkali " + "metal\",\"1\",\"4\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255]," + "null,null]}],[\"create\",\"w127\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":19,\"texts\":[\"20\",\"Ca\",\"Calcium\",\"Alkaline " + "earth " + "metal\",\"2\",\"4\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255]" + ",null,null]}],[\"create\",\"w128\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":20,\"texts\":[\"21\",\"Sc\",\"Scandium\",\"Transition " + "metal\",\"3\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w129\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":21,\"texts\":[\"22\",\"Ti\",\"Titanium\",\"Transition " + "metal\",\"4\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w130\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":22,\"texts\":[\"23\",\"V\",\"Vanadium\",\"Transition " + "metal\",\"5\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w131\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":23,\"texts\":[\"24\",\"Cr\",\"Chromium\",\"Transition " + "metal\",\"6\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w132\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":24,\"texts\":[\"25\",\"Mn\",\"Manganese\",\"Transition " + "metal\",\"7\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w133\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":25,\"texts\":[\"26\",\"Fe\",\"Iron\",\"Transition " + "metal\",\"8\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w134\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":26,\"texts\":[\"27\",\"Co\",\"Cobalt\",\"Transition " + "metal\",\"9\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w135\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":27,\"texts\":[\"28\",\"Ni\",\"Nickel\",\"Transition " + "metal\",\"10\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]" + ",null,null]}],[\"create\",\"w136\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":28,\"texts\":[\"29\",\"Cu\",\"Copper\",\"Transition " + "metal\",\"11\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]" + ",null,null]}],[\"create\",\"w137\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":29,\"texts\":[\"30\",\"Zn\",\"Zinc\",\"Transition " + "metal\",\"12\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]" + ",null,null]}],[\"create\",\"w138\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":30,\"texts\":[\"31\",\"Ga\",\"Gallium\",\"Poor " + "metal\",\"13\",\"4\"],\"cellBackgrounds\":[null,null,null,[238,238,236," + "255],null,null]}],[\"create\",\"w139\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":31,\"texts\":[\"32\",\"Ge\",\"Germanium\"," + "\"Metalloid\",\"14\",\"4\"],\"cellBackgrounds\":[null,null,null,[156,159," + "153,255],null,null]}],[\"create\",\"w140\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":32,\"texts\":[\"33\",\"As\",\"Arsenic\"," + "\"Metalloid\",\"15\",\"4\"],\"cellBackgrounds\":[null,null,null,[156,159," + "153,255],null,null]}],[\"create\",\"w141\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":33,\"texts\":[\"34\",\"Se\",\"Selenium\"," + "\"Nonmetal\",\"16\",\"4\"],\"cellBackgrounds\":[null,null,null,[138,226," + "52,255],null,null]}],[\"create\",\"w142\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":34,\"texts\":[\"35\",\"Br\",\"Bromine\"," + "\"Halogen\",\"17\",\"4\"],\"cellBackgrounds\":[null,null,null,[252,233,79," + "255],null,null]}],[\"create\",\"w143\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":35,\"texts\":[\"36\",\"Kr\",\"Krypton\"," + "\"Noble " + "gas\",\"18\",\"4\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255]," + "null,null]}],[\"create\",\"w144\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":36,\"texts\":[\"37\",\"Rb\",\"Rubidium\",\"Alkali " + "metal\",\"1\",\"5\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255]," + "null,null]}],[\"create\",\"w145\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":37,\"texts\":[\"38\",\"Sr\",\"Strontium\",\"Alkaline " + "earth " + "metal\",\"2\",\"5\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255]" + ",null,null]}],[\"create\",\"w146\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":38,\"texts\":[\"39\",\"Y\",\"Yttrium\",\"Transition " + "metal\",\"3\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w147\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":39,\"texts\":[\"40\",\"Zr\",\"Zirconium\",\"Transition " + "metal\",\"4\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w148\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":40,\"texts\":[\"41\",\"Nb\",\"Niobium\",\"Transition " + "metal\",\"5\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w149\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":41,\"texts\":[\"42\",\"Mo\",\"Molybdenum\",\"Transition " + "metal\",\"6\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w150\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":42,\"texts\":[\"43\",\"Tc\",\"Technetium\",\"Transition " + "metal\",\"7\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w151\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":43,\"texts\":[\"44\",\"Ru\",\"Ruthenium\",\"Transition " + "metal\",\"8\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w152\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":44,\"texts\":[\"45\",\"Rh\",\"Rhodium\",\"Transition " + "metal\",\"9\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w153\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":45,\"texts\":[\"46\",\"Pd\",\"Palladium\",\"Transition " + "metal\",\"10\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]" + ",null,null]}],[\"create\",\"w154\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":46,\"texts\":[\"47\",\"Ag\",\"Silver\",\"Transition " + "metal\",\"11\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]" + ",null,null]}],[\"create\",\"w155\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":47,\"texts\":[\"48\",\"Cd\",\"Cadmium\",\"Transition " + "metal\",\"12\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]" + ",null,null]}],[\"create\",\"w156\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":48,\"texts\":[\"49\",\"In\",\"Indium\",\"Poor " + "metal\",\"13\",\"5\"],\"cellBackgrounds\":[null,null,null,[238,238,236," + "255],null,null]}],[\"create\",\"w157\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":49,\"texts\":[\"50\",\"Sn\",\"Tin\",\"Poor " + "metal\",\"14\",\"5\"],\"cellBackgrounds\":[null,null,null,[238,238,236," + "255],null,null]}],[\"create\",\"w158\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":50,\"texts\":[\"51\",\"Sb\",\"Antimony\"," + "\"Metalloid\",\"15\",\"5\"],\"cellBackgrounds\":[null,null,null,[156,159," + "153,255],null,null]}],[\"create\",\"w159\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":51,\"texts\":[\"52\",\"Te\",\"Tellurium\"," + "\"Metalloid\",\"16\",\"5\"],\"cellBackgrounds\":[null,null,null,[156,159," + "153,255],null,null]}],[\"create\",\"w160\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":52,\"texts\":[\"53\",\"I\",\"Iodine\"," + "\"Halogen\",\"17\",\"5\"],\"cellBackgrounds\":[null,null,null,[252,233,79," + "255],null,null]}],[\"create\",\"w161\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":53,\"texts\":[\"54\",\"Xe\",\"Xenon\"," + "\"Noble " + "gas\",\"18\",\"5\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255]," + "null,null]}],[\"create\",\"w162\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":54,\"texts\":[\"55\",\"Cs\",\"Caesium\",\"Alkali " + "metal\",\"1\",\"6\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255]," + "null,null]}],[\"create\",\"w163\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":55,\"texts\":[\"56\",\"Ba\",\"Barium\",\"Alkaline earth " + "metal\",\"2\",\"6\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255]" + ",null,null]}],[\"create\",\"w164\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":56,\"texts\":[\"57\",\"La\",\"Lanthanum\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w165\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":57,\"texts\":[\"58\",\"Ce\",\"Cerium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w166\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":58,\"texts\":[\"59\",\"Pr\",\"Praseodymium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w167\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":59,\"texts\":[\"60\",\"Nd\",\"Neodymium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w168\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":60,\"texts\":[\"61\",\"Pm\",\"Promethium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w169\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":61,\"texts\":[\"62\",\"Sm\",\"Samarium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w170\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":62,\"texts\":[\"63\",\"Eu\",\"Europium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w171\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":63,\"texts\":[\"64\",\"Gd\",\"Gadolinium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w172\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":64,\"texts\":[\"65\",\"Tb\",\"Terbium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w173\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":65,\"texts\":[\"66\",\"Dy\",\"Dysprosium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w174\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":66,\"texts\":[\"67\",\"Ho\",\"Holmium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w175\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":67,\"texts\":[\"68\",\"Er\",\"Erbium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w176\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":68,\"texts\":[\"69\",\"Tm\",\"Thulium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w177\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":69,\"texts\":[\"70\",\"Yb\",\"Ytterbium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w178\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":70,\"texts\":[\"71\",\"Lu\",\"Lutetium\"," + "\"Lanthanide\",\"3\",\"6\"],\"cellBackgrounds\":[null,null,null,[173,127," + "168,255],null,null]}],[\"create\",\"w179\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":71,\"texts\":[\"72\",\"Hf\",\"Hafnium\"," + "\"Transition " + "metal\",\"4\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w180\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":72,\"texts\":[\"73\",\"Ta\",\"Tantalum\",\"Transition " + "metal\",\"5\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w181\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":73,\"texts\":[\"74\",\"W\",\"Tungsten\",\"Transition " + "metal\",\"6\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w182\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":74,\"texts\":[\"75\",\"Re\",\"Rhenium\",\"Transition " + "metal\",\"7\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w183\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":75,\"texts\":[\"76\",\"Os\",\"Osmium\",\"Transition " + "metal\",\"8\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w184\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":76,\"texts\":[\"77\",\"Ir\",\"Iridium\",\"Transition " + "metal\",\"9\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w185\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":77,\"texts\":[\"78\",\"Pt\",\"Platinum\",\"Transition " + "metal\",\"10\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]" + ",null,null]}],[\"create\",\"w186\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":78,\"texts\":[\"79\",\"Au\",\"Gold\",\"Transition " + "metal\",\"11\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]" + ",null,null]}],[\"create\",\"w187\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":79,\"texts\":[\"80\",\"Hg\",\"Mercury\",\"Transition " + "metal\",\"12\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]" + ",null,null]}],[\"create\",\"w188\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":80,\"texts\":[\"81\",\"Tl\",\"Thallium\",\"Poor " + "metal\",\"13\",\"6\"],\"cellBackgrounds\":[null,null,null,[238,238,236," + "255],null,null]}],[\"create\",\"w189\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":81,\"texts\":[\"82\",\"Pb\",\"Lead\",\"Poor " + "metal\",\"14\",\"6\"],\"cellBackgrounds\":[null,null,null,[238,238,236," + "255],null,null]}],[\"create\",\"w190\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":82,\"texts\":[\"83\",\"Bi\",\"Bismuth\"," + "\"Poor " + "metal\",\"15\",\"6\"],\"cellBackgrounds\":[null,null,null,[238,238,236," + "255],null,null]}],[\"create\",\"w191\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":83,\"texts\":[\"84\",\"Po\",\"Polonium\"," + "\"Metalloid\",\"16\",\"6\"],\"cellBackgrounds\":[null,null,null,[156,159," + "153,255],null,null]}],[\"create\",\"w192\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":84,\"texts\":[\"85\",\"At\",\"Astatine\"," + "\"Halogen\",\"17\",\"6\"],\"cellBackgrounds\":[null,null,null,[252,233,79," + "255],null,null]}],[\"create\",\"w193\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":85,\"texts\":[\"86\",\"Rn\",\"Radon\"," + "\"Noble " + "gas\",\"18\",\"6\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255]," + "null,null]}],[\"create\",\"w194\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":86,\"texts\":[\"87\",\"Fr\",\"Francium\",\"Alkali " + "metal\",\"1\",\"7\"],\"cellBackgrounds\":[null,null,null,[239,41,41,255]," + "null,null]}],[\"create\",\"w195\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":87,\"texts\":[\"88\",\"Ra\",\"Radium\",\"Alkaline earth " + "metal\",\"2\",\"7\"],\"cellBackgrounds\":[null,null,null,[233,185,110,255]" + ",null,null]}],[\"create\",\"w196\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":88,\"texts\":[\"89\",\"Ac\",\"Actinium\",\"Actinide\"," + "\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null," + "null]}],[\"create\",\"w197\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":89,\"texts\":[\"90\",\"Th\",\"Thorium\",\"Actinide\",\"3\"," + "\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}]," + "[\"create\",\"w198\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":90,\"texts\":[\"91\",\"Pa\",\"Protactinium\",\"Actinide\",\"3\"," + "\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}]," + "[\"create\",\"w199\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":91,\"texts\":[\"92\",\"U\",\"Uranium\",\"Actinide\",\"3\",\"7\"]" + ",\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[" + "\"create\",\"w200\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":92,\"texts\":[\"93\",\"Np\",\"Neptunium\",\"Actinide\",\"3\"," + "\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}]," + "[\"create\",\"w201\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":93,\"texts\":[\"94\",\"Pu\",\"Plutonium\",\"Actinide\",\"3\"," + "\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}]," + "[\"create\",\"w202\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":94,\"texts\":[\"95\",\"Am\",\"Americium\",\"Actinide\",\"3\"," + "\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}]," + "[\"create\",\"w203\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":95,\"texts\":[\"96\",\"Cm\",\"Curium\",\"Actinide\",\"3\",\"7\"]" + ",\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}],[" + "\"create\",\"w204\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":96,\"texts\":[\"97\",\"Bk\",\"Berkelium\",\"Actinide\",\"3\"," + "\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}]," + "[\"create\",\"w205\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":97,\"texts\":[\"98\",\"Cf\",\"Californium\",\"Actinide\",\"3\"," + "\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}]," + "[\"create\",\"w206\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":98,\"texts\":[\"99\",\"Es\",\"Einsteinium\",\"Actinide\",\"3\"," + "\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}]," + "[\"create\",\"w207\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":99,\"texts\":[\"100\",\"Fm\",\"Fermium\",\"Actinide\",\"3\"," + "\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}]," + "[\"create\",\"w208\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":100,\"texts\":[\"101\",\"Md\",\"Mendelevium\",\"Actinide\"," + "\"3\",\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null," + "null]}],[\"create\",\"w209\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":101,\"texts\":[\"102\",\"No\",\"Nobelium\",\"Actinide\",\"3\"," + "\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}]," + "[\"create\",\"w210\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":102,\"texts\":[\"103\",\"Lr\",\"Lawrencium\",\"Actinide\",\"3\"," + "\"7\"],\"cellBackgrounds\":[null,null,null,[173,127,168,255],null,null]}]," + "[\"create\",\"w211\",\"rwt.widgets.GridItem\",{\"parent\":\"w99\"," + "\"index\":103,\"texts\":[\"104\",\"Rf\",\"Rutherfordium\",\"Transition " + "metal\",\"4\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w212\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":104,\"texts\":[\"105\",\"Db\",\"Dubnium\",\"Transition " + "metal\",\"5\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w213\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":105,\"texts\":[\"106\",\"Sg\",\"Seaborgium\"," + "\"Transition " + "metal\",\"6\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w214\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":106,\"texts\":[\"107\",\"Bh\",\"Bohrium\",\"Transition " + "metal\",\"7\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w215\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":107,\"texts\":[\"108\",\"Hs\",\"Hassium\",\"Transition " + "metal\",\"8\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w216\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":108,\"texts\":[\"109\",\"Mt\",\"Meitnerium\"," + "\"Transition " + "metal\",\"9\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]," + "null,null]}],[\"create\",\"w217\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":109,\"texts\":[\"110\",\"Ds\",\"Darmstadtium\"," + "\"Transition " + "metal\",\"10\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]" + ",null,null]}],[\"create\",\"w218\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":110,\"texts\":[\"111\",\"Rg\",\"Roentgenium\"," + "\"Transition " + "metal\",\"11\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]" + ",null,null]}],[\"create\",\"w219\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":111,\"texts\":[\"112\",\"Uub\",\"Ununbium\"," + "\"Transition " + "metal\",\"12\",\"7\"],\"cellBackgrounds\":[null,null,null,[252,175,62,255]" + ",null,null]}],[\"create\",\"w220\",\"rwt.widgets.GridItem\",{\"parent\":" + "\"w99\",\"index\":112,\"texts\":[\"113\",\"Uut\",\"Ununtrium\",\"Poor " + "metal\",\"13\",\"7\"],\"cellBackgrounds\":[null,null,null,[238,238,236," + "255],null,null]}],[\"create\",\"w221\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":113,\"texts\":[\"114\",\"Uuq\"," + "\"Ununquadium\",\"Poor " + "metal\",\"14\",\"7\"],\"cellBackgrounds\":[null,null,null,[238,238,236," + "255],null,null]}],[\"create\",\"w222\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":114,\"texts\":[\"115\",\"Uup\"," + "\"Ununpentium\",\"Poor " + "metal\",\"15\",\"7\"],\"cellBackgrounds\":[null,null,null,[238,238,236," + "255],null,null]}],[\"create\",\"w223\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":115,\"texts\":[\"116\",\"Uuh\"," + "\"Ununhexium\",\"Poor " + "metal\",\"16\",\"7\"],\"cellBackgrounds\":[null,null,null,[238,238,236," + "255],null,null]}],[\"create\",\"w224\",\"rwt.widgets.GridItem\",{" + "\"parent\":\"w99\",\"index\":116,\"texts\":[\"117\",\"Uus\"," + "\"Ununseptium\",\"Halogen\",\"17\",\"7\"],\"cellBackgrounds\":[null,null," + "null,[252,233,79,255],null,null]}],[\"create\",\"w225\",\"rwt.widgets." + "GridItem\",{\"parent\":\"w99\",\"index\":117,\"texts\":[\"118\",\"Uuo\"," + "\"Ununoctium\",\"Noble " + "gas\",\"18\",\"7\"],\"cellBackgrounds\":[null,null,null,[114,159,207,255]," + "null,null]}],[\"create\",\"w226\",\"rwt.widgets.Composite\",{\"parent\":" + "\"w97\",\"style\":[\"BORDER\"],\"bounds\":[10,464,988,25],\"children\":[" + "\"w227\"],\"tabIndex\":-1,\"clientArea\":[0,0,986,23]}],[\"create\"," + "\"w227\",\"rwt.widgets.Label\",{\"parent\":\"w226\",\"style\":[\"NONE\"]," + "\"bounds\":[10,10,966,3],\"tabIndex\":-1,\"text\":\"Hydrogen " + "(H)\"}],[\"create\",\"w228\",\"rwt.widgets.Label\",{\"parent\":\"w97\"," + "\"style\":[\"WRAP\"],\"bounds\":[10,499,988,16],\"tabIndex\":-1," + "\"foreground\":[150,150,150,255],\"font\":[[\"Verdana\",\"Lucida " + "Sans\",\"Arial\",\"Helvetica\",\"sans-serif\"],10,false,false],\"text\":" + "\"Shortcuts: [CTRL+F] - Filter | Sort by: [CTRL+R] - Number, [CTRL+Y] - " + "Symbol, [CTRL+N] - Name, [CTRL+S] - Series, [CTRL+G] - Group, [CTRL+E] - " + "Period\"}],[\"set\",\"w1\",{\"focusControl\":\"w99\"}],[\"call\",\"rwt." + "client.BrowserNavigation\",\"addToHistory\",{\"entries\":[[" + "\"tableviewer\",\"TableViewer\"]]}]]}"; + +class HashIndexTable { + std::array _hashTable{}; + + public: + void add(const std::string& name, int32_t index) { + int32_t slot = hashSlotFor(name); + if (index < 0xff) { + // increment by 1, 0 stands for empty + _hashTable[slot] = (index + 1) & 0xff; + } else { + _hashTable[slot] = 0; + } + } + + [[nodiscard]] int32_t get(const std::string& name) const { + int32_t slot = hashSlotFor(name); + // subtract 1, 0 stands for empty + return (_hashTable[slot] & 0xff) - 1; + } + + private: + [[nodiscard]] int32_t stringHash(const std::string& s) const { + // this is not a proper hash, but sufficient for the benchmark, + // and very portable! + return s.size() * 1402589; + } + + [[nodiscard]] int32_t hashSlotFor(const std::string& element) const { + return stringHash(element) & _hashTable.size() - 1; + } +}; + +class JsonArray; +class JsonObject; + +class JsonValue { + public: + JsonValue() = default; + virtual ~JsonValue() = default; + + [[nodiscard]] virtual bool isObject() const { return false; } + [[nodiscard]] virtual bool isArray() const { return false; } + [[nodiscard]] virtual bool isNumber() const { return false; } + [[nodiscard]] virtual bool isString() const { return false; } + [[nodiscard]] virtual bool isBoolean() const { return false; } + [[nodiscard]] virtual bool isTrue() const { return false; } + [[nodiscard]] virtual bool isFalse() const { return false; } + [[nodiscard]] virtual bool isNull() const { return false; } + + [[nodiscard]] virtual const JsonObject* asObject() const { + throw Error("Not an object: " + toString()); + } + + [[nodiscard]] virtual const JsonArray* asArray() const { + throw Error("Not an array: " + toString()); + } + + [[nodiscard]] virtual string toString() const { return ""; } +}; + +class JsonArray : public JsonValue { + private: + Vector _values{}; + + public: + JsonArray() = default; + ~JsonArray() override { _values.destroyValues(); } + + void add(const JsonValue* value) { + if (value == nullptr) { + throw Error("value is null"); + } + _values.append(value); + } + + [[nodiscard]] size_t size() const { return _values.size(); } + + [[nodiscard]] const JsonValue* get(int index) const { + return _values.at(index); + } + + [[nodiscard]] bool isArray() const override { return true; } + + [[nodiscard]] const JsonArray* asArray() const override { return this; } +}; + +class JsonLiteral : public JsonValue { + private: + string _value; + bool _isNull; + bool _isTrue; + bool _isFalse; + + JsonLiteral(string value, bool isNull, bool isTrue, bool isFalse) + : _value(value), _isNull(isNull), _isTrue(isTrue), _isFalse(isFalse) {} + + public: + JsonLiteral(string value) + : _value(value), + _isNull(value == "null"), + _isTrue(value == "true"), + _isFalse(value == "false") {} + + [[nodiscard]] bool isNull() const override { return _isNull; } + [[nodiscard]] bool isTrue() const override { return _isTrue; } + [[nodiscard]] bool isFalse() const override { return _isFalse; } + [[nodiscard]] bool isBoolean() const override { return _isTrue || _isFalse; } + + [[nodiscard]] string toString() const override { return _value; } + + static JsonLiteral* createNull() { + return new JsonLiteral("null", true, false, false); + } + + static JsonLiteral* createTrue() { + return new JsonLiteral("true", false, true, false); + } + + static JsonLiteral* createFalse() { + return new JsonLiteral("false", false, false, true); + } +}; + +class JsonNumber : public JsonValue { + private: + string _string; + + public: + JsonNumber(string string) : _string(string) { + if (string.empty()) { + throw Error("value is null"); + } + } + + [[nodiscard]] string toString() const override { return _string; } + [[nodiscard]] bool isNumber() const override { return true; } +}; + +class JsonObject : public JsonValue { + private: + Vector _names{}; + Vector _values{}; + HashIndexTable _table{}; + + int32_t indexOf(string name) const { + int32_t index = _table.get(name); + if (index != -1 && name == _names.at(index)) { + return index; + } + throw Error("not yet implemented, not relevant for the benchmark"); + } + + public: + JsonObject() = default; + ~JsonObject() override { _values.destroyValues(); } + + void add(string name, const JsonValue* value) { + if (name.empty()) { + throw Error("name is null"); + } + if (value == nullptr) { + throw Error("value is null"); + } + _table.add(name, _names.size()); + _names.append(name); + _values.append(value); + } + + const JsonValue* get(string name) const { + if (name.empty()) { + throw Error("name is null"); + } + int32_t index = indexOf(name); + return index == -1 ? nullptr : _values.at(index); + } + + [[nodiscard]] size_t size() const { return _names.size(); } + [[nodiscard]] bool isEmpty() const { return _names.isEmpty(); } + [[nodiscard]] bool isObject() const override { return true; } + const JsonObject* asObject() const override { return this; } +}; + +class JsonString : public JsonValue { + private: + string _string; + + public: + JsonString(string string) : _string(string) {} + + [[nodiscard]] bool isString() const override { return true; } +}; + +class ParseException : virtual public std::exception { + private: + size_t _offset; + int32_t _line; + int32_t _column; + string _what; + + public: + ParseException(string message, size_t offset, int32_t line, int32_t column) + : _offset(offset), + _line(line), + _column(column), + _what(message + " at " + std::to_string(line) + ":" + + std::to_string(column)) {} + + [[nodiscard]] int32_t getOffset() const { return _offset; } + [[nodiscard]] int32_t getLine() const { return _line; } + [[nodiscard]] int32_t getColumn() const { return _column; } + [[nodiscard]] const char* what() const noexcept override { + return (_what.c_str()); + } +}; + +class JsonPureStringParser { + private: + string _input; + size_t _index{SIZE_MAX}; + int32_t _line{1}; + int32_t _column{0}; + string _current{""}; + string _captureBuffer{""}; + size_t _captureStart{SIZE_MAX}; + + const JsonValue* readValue() { + if (_current == "n") { + return readNull(); + } else if (_current == "t") { + return readTrue(); + } else if (_current == "f") { + return readFalse(); + } else if (_current == "\"") { + return readString(); + } else if (_current == "[") { + return readArray(); + } else if (_current == "{") { + return readObject(); + } else if (_current == "-" || _current == "0" || _current == "1" || + _current == "2" || _current == "3" || _current == "4" || + _current == "5" || _current == "6" || _current == "7" || + _current == "8" || _current == "9") { + return readNumber(); + } else + throw expected("value"); + } + + JsonObject* readObject() { + read(); + JsonObject* object = new JsonObject(); + skipWhiteSpace(); + if (readChar("}")) { + return object; + } + do { + skipWhiteSpace(); + string name = readName(); + skipWhiteSpace(); + if (!readChar(":")) { + throw expected("':'"); + } + skipWhiteSpace(); + + object->add(name, readValue()); + skipWhiteSpace(); + } while (readChar(",")); + if (!readChar("}")) { + throw expected("',' or '}'"); + } + return object; + } + + string readName() { + if (_current != "\"") { + throw expected("name"); + } + return readStringInternal(); + } + + JsonArray* readArray() { + read(); + JsonArray* array = new JsonArray(); + skipWhiteSpace(); + if (readChar("]")) { + return array; + } + do { + skipWhiteSpace(); + array->add(readValue()); + skipWhiteSpace(); + } while (readChar(",")); + + if (!readChar("]")) { + throw expected("',' or ']'"); + } + return array; + } + + const JsonValue* readNull() { + read(); + readRequiredChar("u"); + readRequiredChar("l"); + readRequiredChar("l"); + return JsonLiteral::createNull(); + } + + const JsonValue* readTrue() { + read(); + readRequiredChar("r"); + readRequiredChar("u"); + readRequiredChar("e"); + return JsonLiteral::createTrue(); + } + + const JsonValue* readFalse() { + read(); + readRequiredChar("a"); + readRequiredChar("l"); + readRequiredChar("s"); + readRequiredChar("e"); + return JsonLiteral::createFalse(); + } + + void readRequiredChar(string ch) { + if (!readChar(ch)) { + throw expected("'" + ch + "'"); + } + } + + const JsonValue* readString() { return new JsonString(readStringInternal()); } + + string readStringInternal() { + read(); + startCapture(); + while (_current != "\"") { + if (_current == "\\") { + pauseCapture(); + readEscape(); + startCapture(); + } else { + read(); + } + } + string string = endCapture(); + read(); + return string; + } + + void readEscape() { + read(); + if (_current == "\"" || _current == "/" || _current == "\\") + _captureBuffer += _current; + else if (_current == "b") + _captureBuffer += "\b"; + else if (_current == "f") + _captureBuffer += "\f"; + else if (_current == "n") + _captureBuffer += "\n"; + else if (_current == "r") + _captureBuffer += "\r"; + else if (_current == "t") + _captureBuffer += "\t"; + else + throw expected("valid escape sequence"); + read(); + } + + const JsonValue* readNumber() { + startCapture(); + readChar("-"); + string firstDigit = _current; + if (!readDigit()) { + throw expected("digit"); + } + if (firstDigit != "0") { + while (readDigit()) { + } + } + readFraction(); + readExponent(); + return new JsonNumber(endCapture()); + } + + bool readFraction() { + if (!readChar(".")) { + return false; + } + if (!readDigit()) { + throw expected("digit"); + } + while (readDigit()) { + } + + return true; + } + + bool readExponent() { + if (!readChar("e") && !readChar("E")) { + return false; + } + if (!readChar("+")) { + readChar("-"); + } + if (!readDigit()) { + throw expected("digit"); + } + + while (readDigit()) { + } + return true; + } + + bool readChar(string ch) { + if (_current != ch) { + return false; + } + read(); + return true; + } + + bool readDigit() { + if (!isDigit()) { + return false; + } + read(); + return true; + } + + void skipWhiteSpace() { + while (isWhiteSpace()) { + read(); + } + } + + void read() { + if ("\n" == _current) { + _line += 1; + _column = 0; + } + _index += 1; + if (_index < _input.length()) { + _current = _input.substr(_index, 1); + } else { + _current = ""; + } + } + + void startCapture() { _captureStart = _index; } + + void pauseCapture() { + size_t _end = _current == "" ? _index : _index - 1; + _captureBuffer += _input.substr(_captureStart, _end - _captureStart + 1); + _captureStart = -1; + } + + string endCapture() { + size_t _end = _current == "" ? _index : _index - 1; + string captured; + if ("" == _captureBuffer) { + captured = _input.substr(_captureStart, _end - _captureStart + 1); + } else { + _captureBuffer += _input.substr(_captureStart, _end - _captureStart + 1); + captured = _captureBuffer; + _captureBuffer = ""; + } + _captureStart = -1; + return captured; + } + + ParseException expected(string expected) { + if (isEndOfText()) { + return error("Unexpected end of input"); + } + + return error("Expected " + expected); + } + + ParseException error(string message) { + return ParseException(message, _index, _line, _column - 1); + } + + bool isWhiteSpace() { + return " " == _current || "\t" == _current || "\n" == _current || + "\r" == _current; + } + + bool isDigit() { + return "0" == _current || "1" == _current || "2" == _current || + "3" == _current || "4" == _current || "5" == _current || + "6" == _current || "7" == _current || "8" == _current || + "9" == _current; + } + + bool isEndOfText() { return _current == ""; } + + public: + JsonPureStringParser(string string) : _input(string) {} + + const JsonValue* parse() { + read(); + skipWhiteSpace(); + const JsonValue* result = readValue(); + skipWhiteSpace(); + if (!isEndOfText()) { + throw Error("Unexpected character"); + } + return result; + } +}; + +class Json : public Benchmark { + private: + public: + void* benchmark() override { + JsonPureStringParser parser{rapBenchmarkMinified}; + const JsonValue* const result = parser.parse(); + return const_cast( + result); // TODO make benchmark return const void* or std::any or so + } + + bool has_expected_content(const JsonValue* result) { + if (!result->isObject()) { + return false; + } + auto* resultObject = result->asObject(); + if (!resultObject->get("head")->isObject()) { + return false; + } + if (!resultObject->get("operations")->isArray()) { + return false; + } + auto* resultArray = resultObject->get("operations")->asArray(); + return resultArray->size() == 156; + } + + bool verify_result(void* r) override { + auto* const result = reinterpret_cast(r); + const bool doesVerify = has_expected_content(result); + delete result; + return doesVerify; + } +}; \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonArray.cpp b/benchmarks/C++/src/json/JsonArray.cpp deleted file mode 100644 index b6adf787..00000000 --- a/benchmarks/C++/src/json/JsonArray.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "JsonArray.h" - -namespace json { - JsonArray::JsonArray() { - _values = make_shared>>(); - } - - void JsonArray::add(shared_ptr value) { - if (value == nullptr) { - throw Error("value is null"); - } - _values->append(value); - } - - int JsonArray::size() { - return _values->size(); - } - - shared_ptr JsonArray::get(int index) { - return _values->at(index); - } - - bool JsonArray::isArray() { - return true; - } - - shared_ptr JsonArray::asArray() { - return shared_from_this(); - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonArray.h b/benchmarks/C++/src/json/JsonArray.h deleted file mode 100644 index f898257a..00000000 --- a/benchmarks/C++/src/json/JsonArray.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef JSONARRAY -#define JSONARRAY - -#include "../som/Vector.cpp" -#include "JsonValue.h" -#include -#include "../som/Error.cpp" - -namespace json { - class JsonArray : public JsonValue, public std::enable_shared_from_this { - private: - shared_ptr>> _values; - - public: - - JsonArray(); - - void add(shared_ptr value); - int size(); - shared_ptr get(int index); - bool isArray() override; - shared_ptr asArray() override; - }; -} - -#endif //JSONARRAY \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonLiteral.cpp b/benchmarks/C++/src/json/JsonLiteral.cpp deleted file mode 100644 index db35d0dc..00000000 --- a/benchmarks/C++/src/json/JsonLiteral.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "JsonLiteral.h" - - -namespace json { - - shared_ptr JsonLiteral::NNULL = make_shared("null"); - shared_ptr JsonLiteral::TRUE = make_shared("true"); - shared_ptr JsonLiteral::FALSE = make_shared("false"); - - JsonLiteral::JsonLiteral(string value) { - _value = value; - _isNull = (value == "null"); - _isTrue = (value == "true"); - _isFalse = (value == "false"); - } - - // Method to get the string representation of the literal - string JsonLiteral::toString() { - return _value; - } - - // Check if the literal is null - bool JsonLiteral::isNull() { - return _isNull; - } - - // Check if the literal is true - bool JsonLiteral::isTrue() { - return _isTrue; - } - - // Check if the literal is false - bool JsonLiteral::isFalse() { - return _isFalse; - } - - // Check if the literal is a boolean value (true or false) - bool JsonLiteral::isBoolean() { - return _isTrue || _isFalse; - } - -} \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonLiteral.h b/benchmarks/C++/src/json/JsonLiteral.h deleted file mode 100644 index 6f63de87..00000000 --- a/benchmarks/C++/src/json/JsonLiteral.h +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include "JsonValue.h" - -using namespace std; - -namespace json { - class JsonLiteral: public JsonValue { - private: - string _value; - bool _isNull; - bool _isTrue; - bool _isFalse; - - public: - static shared_ptr NNULL; - static shared_ptr TRUE; - static shared_ptr FALSE; - - JsonLiteral(string value); - - string toString() override; - bool isNull() override; - bool isTrue() override; - bool isFalse() override; - bool isBoolean() override; - - }; -} diff --git a/benchmarks/C++/src/json/JsonNumber.cpp b/benchmarks/C++/src/json/JsonNumber.cpp deleted file mode 100644 index d28f414a..00000000 --- a/benchmarks/C++/src/json/JsonNumber.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "JsonNumber.h" - -using namespace std; - -namespace json { - JsonNumber::JsonNumber(string string) { - _string = string; - if (string.empty()) { - throw Error("value is null"); - } - } - - string JsonNumber::toString() { - return _string; - } - - bool JsonNumber::isNumber() { - return true; - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonNumber.h b/benchmarks/C++/src/json/JsonNumber.h deleted file mode 100644 index 5b9fb11a..00000000 --- a/benchmarks/C++/src/json/JsonNumber.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef JSONUMBER -#define JSONUMBER - -#include -#include "../som/Error.cpp" -#include "JsonValue.h" - -using namespace std; - -namespace json { - class JsonNumber : public JsonValue { - private: - string _string; - - public: - JsonNumber(string string); - - string toString() override; - bool isNumber() override; - }; -} - -#endif //JSONUMBER \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonObject.cpp b/benchmarks/C++/src/json/JsonObject.cpp deleted file mode 100644 index cedd9a0e..00000000 --- a/benchmarks/C++/src/json/JsonObject.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "JsonObject.h" - -namespace json { - JsonObject::JsonObject() { - _names = make_shared>(); - _values = make_shared>>(); - }; - - int JsonObject::indexOf(string name) { - int index = _table.find(name)->second; - if (index != -1 && name == _names->at(index)) { - return index; - } - throw new Error("NotImplemented"); - } - - - void JsonObject::add(string name, shared_ptr value) { - if (name.empty()) { - throw Error ("name is null"); - } - if (value == nullptr) { - throw Error ("value is null"); - } - _table[name] = _names->size(); - _names->append(name); - _values->append(value); - } - - shared_ptr JsonObject::get(string name) { - if (name.empty()) { - throw Error ("name is null"); - } - int index = indexOf(name); - return index == -1 ? nullptr : _values->at(index); - } - - int JsonObject::size() const { - return static_cast(_names->size()); - } - - bool JsonObject::isEmpty() const { - return _names->isEmpty(); - } - - bool JsonObject::isObject() { - return true; - } - - shared_ptr JsonObject::asObject() { - return shared_from_this(); - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonObject.h b/benchmarks/C++/src/json/JsonObject.h deleted file mode 100644 index 926a2b2c..00000000 --- a/benchmarks/C++/src/json/JsonObject.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef JSONNUMBER -#define JSONNUMBER - -#include "../som/Vector.cpp" -#include "JsonValue.h" -#include "../som/Error.cpp" -#include -#include -#include - -using namespace std; - -namespace json { - class JsonObject : public JsonValue, public std::enable_shared_from_this { - private: - shared_ptr> _names; - shared_ptr>> _values; - map _table; - - int indexOf(string name); - - public: - JsonObject(); - - void add(string name, shared_ptr value); - shared_ptr get(string name); - int size() const; - bool isEmpty() const; - bool isObject() override; - shared_ptr asObject() override; - }; -} - -#endif //JSONNUMBER diff --git a/benchmarks/C++/src/json/JsonPureStringParser.cpp b/benchmarks/C++/src/json/JsonPureStringParser.cpp deleted file mode 100644 index 7804163c..00000000 --- a/benchmarks/C++/src/json/JsonPureStringParser.cpp +++ /dev/null @@ -1,305 +0,0 @@ -#include "JsonPureStringParser.h" - -namespace json { - - shared_ptr JsonPureStringParser::readValue() { - if (_current == "n") { - return readNull(); - } else if (_current == "t") { - return readTrue(); - } else if (_current == "f") { - return readFalse(); - } else if (_current == "\"") { - return readString(); - } else if (_current == "[") { - return readArray(); - } else if (_current == "{") { - return readObject(); - } - else if (_current == "-" || _current == "0" || _current == "1" || _current == "2" || _current == "3" || _current == "4" - || _current == "5" || _current == "6" || _current == "7" || _current == "8" || _current == "9") { - return readNumber(); - } - else - throw expected("value"); - } - - shared_ptr JsonPureStringParser::readObject() { - read(); - shared_ptr object = make_shared(); - skipWhiteSpace(); - if (readChar("}")) { - return object; - } - do { - skipWhiteSpace(); - string name = readName(); - skipWhiteSpace(); - if (!readChar(":")) { - throw expected("':'"); - } - skipWhiteSpace(); - - object->add(name, readValue()); - skipWhiteSpace(); - } - while (readChar(",")); - if (!readChar("}")) { - throw expected("',' or '}'"); - } - return object; - } - - string JsonPureStringParser::readName() { - if (_current != "\"") { - throw expected("name"); - } - return readStringInternal(); - } - - shared_ptr JsonPureStringParser::readArray() { - read(); - shared_ptr array = make_shared(); - skipWhiteSpace(); - if (readChar("]")) { - return array; - } - do { - skipWhiteSpace(); - array->add(readValue()); - skipWhiteSpace(); - } while (readChar(",")); - - if (!readChar("]")) { - throw expected("',' or ']'"); - } - return array; - } - - shared_ptr JsonPureStringParser::readNull() { - read(); - readRequiredChar("u"); - readRequiredChar("l"); - readRequiredChar("l"); - return JsonLiteral::NNULL; - } - - shared_ptr JsonPureStringParser::readTrue() { - read(); - readRequiredChar("r"); - readRequiredChar("u"); - readRequiredChar("e"); - return JsonLiteral::TRUE; - } - - shared_ptr JsonPureStringParser::readFalse() { - read(); - readRequiredChar("a"); - readRequiredChar("l"); - readRequiredChar("s"); - readRequiredChar("e"); - return JsonLiteral::FALSE; - } - - void JsonPureStringParser::readRequiredChar(string ch) { - if (!readChar(ch)) { - throw expected("'" + ch + "'"); - } - } - - shared_ptr JsonPureStringParser::readString() { - return make_shared(readStringInternal()); - } - - string JsonPureStringParser::readStringInternal() { - read(); - startCapture(); - while (_current != "\"") { - if (_current == "\\") { - pauseCapture(); - readEscape(); - startCapture(); - } else { - read(); - } - } - string string = endCapture(); - read(); - return string; - } - - void JsonPureStringParser::readEscape() { - read(); - if (_current == "\"" || _current == "/" || _current == "\\") - _captureBuffer += _current; - else if (_current == "b") - _captureBuffer += "\b"; - else if (_current == "f") - _captureBuffer += "\f"; - else if (_current == "n") - _captureBuffer += "\n"; - else if (_current == "r") - _captureBuffer += "\r"; - else if (_current == "t") - _captureBuffer += "\t"; - else - throw expected("valid escape sequence"); - read(); - } - - shared_ptr JsonPureStringParser::readNumber() { - startCapture(); - readChar("-"); - string firstDigit = _current; - if (!readDigit()) { - throw expected("digit"); - } - if (firstDigit != "0") { - while (readDigit()) { } - } - readFraction(); - readExponent(); - return make_shared(endCapture()); - } - - bool JsonPureStringParser::readFraction() { - if (!readChar(".")) { - return false; - } - if (!readDigit()) { - throw expected("digit"); - } - while (readDigit()) { } - return true; - } - - bool JsonPureStringParser::readExponent() { - if (!readChar("e") && !readChar("E")) { - return false; - } - if (!readChar("+")) { - readChar("-"); - } - if (!readDigit()) { - throw expected("digit"); - } - - while (readDigit()) { } - return true; - } - - bool JsonPureStringParser::readChar(string ch) { - if (_current != ch) { - return false; - } - read(); - return true; - } - - bool JsonPureStringParser::readDigit() { - if (!isDigit()) { - return false; - } - read(); - return true; - } - - void JsonPureStringParser::skipWhiteSpace() { - while (isWhiteSpace()) { - read(); - } - } - - void JsonPureStringParser::read() { - if ("\n" == _current) { - _line++; - _column = 0; - } - _index++; - if (_index < _input.length()) { - _current = _input.substr(_index, 1); - } else { - _current = ""; - } - } - - void JsonPureStringParser::startCapture() { - _captureStart = _index; - } - - void JsonPureStringParser::pauseCapture() { - int _end = _current == "" ? _index : _index - 1; - _captureBuffer += _input.substr(_captureStart, _end - _captureStart + 1); - _captureStart = -1; - } - - string JsonPureStringParser::endCapture() { - int _end = _current == "" ? _index : _index - 1; - string captured; - if ("" == _captureBuffer) { - captured = _input.substr(_captureStart, _end - _captureStart + 1); - } else { - _captureBuffer += _input.substr(_captureStart, _end - _captureStart + 1); - captured = _captureBuffer; - _captureBuffer = ""; - } - _captureStart = -1; - return captured; - } - - ParseException JsonPureStringParser::expected(string expected) { - if (isEndOfText()) { - return error("Unexpected end of input"); - } - - return error("Expected " + expected); - } - - ParseException JsonPureStringParser::error(string message) { - return ParseException(message, _index, _line, _column - 1); - } - - bool JsonPureStringParser::isWhiteSpace() { - return " " == _current || "\t" == _current || "\n" == _current || "\r" == _current; - } - - - bool JsonPureStringParser::isDigit() { - return "0" == _current || - "1" == _current || - "2" == _current || - "3" == _current || - "4" == _current || - "5" == _current || - "6" == _current || - "7" == _current || - "8" == _current || - "9" == _current; - } - - bool JsonPureStringParser::isEndOfText() { - return _current == ""; - } - - JsonPureStringParser::JsonPureStringParser(string string) { - _input = string; - _index = -1; - _line = 1; - _captureStart = -1; - _column = 0; - _current = ""; - _captureBuffer = ""; - } - - shared_ptr JsonPureStringParser::parse() { - read(); - skipWhiteSpace(); - shared_ptr result = readValue(); - skipWhiteSpace(); - if (!isEndOfText()) { - throw Error("Unexpected character"); - } - return result; - } - -} diff --git a/benchmarks/C++/src/json/JsonPureStringParser.h b/benchmarks/C++/src/json/JsonPureStringParser.h deleted file mode 100644 index 19c36dfd..00000000 --- a/benchmarks/C++/src/json/JsonPureStringParser.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef JSONPURESTRINGPARSER -#define JSONPURESTRINGPARSER - - -#include -#include -#include "../som/Error.cpp" -#include "JsonArray.h" -#include "JsonObject.h" -#include "ParseException.h" -#include "JsonLiteral.h" -#include "JsonNumber.h" -#include "JsonString.h" - -using namespace std; - -namespace json { - class JsonPureStringParser { - private: - string _input; - int _index; - int _line; - int _column; - string _current; - string _captureBuffer; - int _captureStart; - - shared_ptr readValue(); - shared_ptr readObject(); - string readName(); - shared_ptr readArray(); - shared_ptr readNull(); - shared_ptr readTrue(); - shared_ptr readFalse(); - void readRequiredChar(string ch); - shared_ptr readString(); - string readStringInternal(); - void readEscape(); - shared_ptr readNumber(); - bool readFraction(); - bool readExponent(); - bool readChar(string ch); - bool readDigit(); - void skipWhiteSpace(); - void read(); - void startCapture(); - void pauseCapture(); - string endCapture(); - ParseException expected(string expected); - ParseException error(string message); - bool isWhiteSpace(); - bool isDigit(); - bool isEndOfText(); - - public: - JsonPureStringParser(string string); - - shared_ptr parse(); - - }; -} - - -#endif //JSONPURESTRINGPARSER \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonString.cpp b/benchmarks/C++/src/json/JsonString.cpp deleted file mode 100644 index a6eebd1a..00000000 --- a/benchmarks/C++/src/json/JsonString.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "JsonString.h" - - -namespace json { - - JsonString::JsonString(string string) { - _string = string; - } - - bool JsonString::isString() { - return true; - } -} diff --git a/benchmarks/C++/src/json/JsonString.h b/benchmarks/C++/src/json/JsonString.h deleted file mode 100644 index 755aa180..00000000 --- a/benchmarks/C++/src/json/JsonString.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef JSONSTRING -#define JSONSTRING - -#include -#include "JsonValue.h" - -using namespace std; - -namespace json { - class JsonString : public JsonValue { - private: - string _string; - public: - - JsonString(string string); - - bool isString() override; - }; -} - -#endif //JSONSTRING \ No newline at end of file diff --git a/benchmarks/C++/src/json/JsonValue.cpp b/benchmarks/C++/src/json/JsonValue.cpp deleted file mode 100644 index e7bf5e2e..00000000 --- a/benchmarks/C++/src/json/JsonValue.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "JsonValue.h" - -namespace json { - - bool JsonValue::isObject() { - return false; - } - - - bool JsonValue::isArray() { - return false; - } - - - bool JsonValue::isNumber() { - return false; - } - - - bool JsonValue::isString() { - return false; - } - - - bool JsonValue::isBoolean() { - return false; - } - - - bool JsonValue::isTrue() { - return false; - } - - - bool JsonValue::isFalse() { - return false; - } - - - bool JsonValue::isNull() { - return false; - } - - shared_ptr JsonValue::asObject() { - throw Error("Not an object: " + toString()); - } - - shared_ptr JsonValue::asArray() { - throw Error("Not an array: " + toString()); - } - - string JsonValue::toString() { - return ""; - } -} diff --git a/benchmarks/C++/src/json/JsonValue.h b/benchmarks/C++/src/json/JsonValue.h deleted file mode 100644 index 8e6c617f..00000000 --- a/benchmarks/C++/src/json/JsonValue.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef JSONVALUE -#define JSONVALUE - -#include -#include "../som/Error.cpp" - -using namespace std; - -namespace json { - - class JsonArray; - class JsonObject; - - class JsonValue { - public: - JsonValue() = default; - - virtual bool isObject(); - virtual bool isArray(); - virtual bool isNumber(); - virtual bool isString(); - virtual bool isBoolean(); - virtual bool isTrue(); - virtual bool isFalse(); - virtual bool isNull(); - virtual shared_ptr asObject(); - virtual shared_ptr asArray(); - virtual string toString(); - }; -} - -#endif //JSONVALUE \ No newline at end of file diff --git a/benchmarks/C++/src/json/ParseException.cpp b/benchmarks/C++/src/json/ParseException.cpp deleted file mode 100644 index d943af54..00000000 --- a/benchmarks/C++/src/json/ParseException.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "ParseException.h" - -namespace json { - ParseException::ParseException(string message, int offset, int line, int column) { - _offset = offset; - _line = line; - _column = column; - _what = message + " at " + to_string(line) + ":" + to_string(column); - } - - int ParseException::getOffset() { - return _offset; - } - - int ParseException::getLine() { - return _line; - } - - int ParseException::getColumn() { - return _column; - } - - const char *ParseException::what() const throw() { - return (_what.c_str()); - } - -} \ No newline at end of file diff --git a/benchmarks/C++/src/json/ParseException.h b/benchmarks/C++/src/json/ParseException.h deleted file mode 100644 index 7fc2b83c..00000000 --- a/benchmarks/C++/src/json/ParseException.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef PARSEEXCEPTION -#define PARSEEXCEPTION - -#include - -using namespace std; - -namespace json { - class ParseException : virtual public exception { - private: - int _offset; - int _line; - int _column; - string _what; - - public: - ParseException(string message, int offset, int line, int column); - - int getOffset(); - int getLine(); - int getColumn(); - const char *what() const throw(); - }; -} - -#endif //PARSEEXCEPTION \ No newline at end of file diff --git a/benchmarks/C++/src/run.h b/benchmarks/C++/src/run.h index 4a84f150..ce5b94b4 100644 --- a/benchmarks/C++/src/run.h +++ b/benchmarks/C++/src/run.h @@ -5,6 +5,7 @@ #include "bounce.h" #include "deltablue.h" +#include "json.h" #include "list.h" #include "mandelbrot.h" #include "nbody.h" @@ -54,6 +55,9 @@ class Run { if (name == "Bounce") { return []() -> Benchmark* { return new Bounce(); }; } + if (name == "Json") { + return []() -> Benchmark* { return new Json(); }; + } if (name == "List") { return []() -> Benchmark* { return new List(); }; } diff --git a/benchmarks/C++/src/som/vector.h b/benchmarks/C++/src/som/vector.h index c0ec2b07..07e6e757 100644 --- a/benchmarks/C++/src/som/vector.h +++ b/benchmarks/C++/src/som/vector.h @@ -88,6 +88,12 @@ class Vector { ~Vector() { delete[] storage; } + void destroyValues() { + for (size_t i = _firstIdx; i < _lastIdx; i++) { + delete storage[i]; + } + } + [[nodiscard]] E atPtr(size_t idx) const { if (idx >= _lastIdx - _firstIdx) { return nullptr; From 7aa09343f6bdfd16f82dad642adc9d3601bdab8a Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sat, 6 Jan 2024 18:42:16 +0000 Subject: [PATCH 12/40] [C++] Added Richards port by Hugo Jenningros Signed-off-by: Stefan Marr --- benchmarks/C++/src/Richards.cpp | 13 + benchmarks/C++/src/Richards.h | 18 ++ .../C++/src/richards/DeviceTaskDataRecord.cpp | 17 ++ .../C++/src/richards/DeviceTaskDataRecord.h | 24 ++ .../src/richards/HandlerTaskDataRecord.cpp | 34 +++ .../C++/src/richards/HandlerTaskDataRecord.h | 30 +++ .../C++/src/richards/IdleTaskDataRecord.cpp | 25 ++ .../C++/src/richards/IdleTaskDataRecord.h | 23 ++ benchmarks/C++/src/richards/Packet.cpp | 50 ++++ benchmarks/C++/src/richards/Packet.h | 38 +++ benchmarks/C++/src/richards/RBObject.cpp | 32 +++ benchmarks/C++/src/richards/RBObject.h | 37 +++ benchmarks/C++/src/richards/Scheduler.cpp | 241 ++++++++++++++++++ benchmarks/C++/src/richards/Scheduler.h | 56 ++++ .../C++/src/richards/TaskControlBlock.cpp | 61 +++++ .../C++/src/richards/TaskControlBlock.h | 40 +++ benchmarks/C++/src/richards/TaskState.cpp | 73 ++++++ benchmarks/C++/src/richards/TaskState.h | 36 +++ .../C++/src/richards/WorkerTaskDataRecord.cpp | 24 ++ .../C++/src/richards/WorkerTaskDataRecord.h | 17 ++ 20 files changed, 889 insertions(+) create mode 100644 benchmarks/C++/src/Richards.cpp create mode 100644 benchmarks/C++/src/Richards.h create mode 100644 benchmarks/C++/src/richards/DeviceTaskDataRecord.cpp create mode 100644 benchmarks/C++/src/richards/DeviceTaskDataRecord.h create mode 100644 benchmarks/C++/src/richards/HandlerTaskDataRecord.cpp create mode 100644 benchmarks/C++/src/richards/HandlerTaskDataRecord.h create mode 100644 benchmarks/C++/src/richards/IdleTaskDataRecord.cpp create mode 100644 benchmarks/C++/src/richards/IdleTaskDataRecord.h create mode 100644 benchmarks/C++/src/richards/Packet.cpp create mode 100644 benchmarks/C++/src/richards/Packet.h create mode 100644 benchmarks/C++/src/richards/RBObject.cpp create mode 100644 benchmarks/C++/src/richards/RBObject.h create mode 100644 benchmarks/C++/src/richards/Scheduler.cpp create mode 100644 benchmarks/C++/src/richards/Scheduler.h create mode 100644 benchmarks/C++/src/richards/TaskControlBlock.cpp create mode 100644 benchmarks/C++/src/richards/TaskControlBlock.h create mode 100644 benchmarks/C++/src/richards/TaskState.cpp create mode 100644 benchmarks/C++/src/richards/TaskState.h create mode 100644 benchmarks/C++/src/richards/WorkerTaskDataRecord.cpp create mode 100644 benchmarks/C++/src/richards/WorkerTaskDataRecord.h diff --git a/benchmarks/C++/src/Richards.cpp b/benchmarks/C++/src/Richards.cpp new file mode 100644 index 00000000..113b5557 --- /dev/null +++ b/benchmarks/C++/src/Richards.cpp @@ -0,0 +1,13 @@ +#include "Richards.h" + +namespace richards { + + bool Richards::verifyResult(std::any result) { + bool result_cast = std::any_cast(result); + return result_cast; + } + + std::any Richards::benchmark() { + return (Scheduler()).start(); + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/Richards.h b/benchmarks/C++/src/Richards.h new file mode 100644 index 00000000..ec2fab1f --- /dev/null +++ b/benchmarks/C++/src/Richards.h @@ -0,0 +1,18 @@ +#ifndef RICHARDS +#define RICHARDS + + +#include "Benchmark.h" +#include "richards/Scheduler.h" + +namespace richards { + class Richards : public Benchmark { + + public: + + bool verifyResult(std::any result) override; + std::any benchmark() override; + }; +}; + +#endif // RICHARDS \ No newline at end of file diff --git a/benchmarks/C++/src/richards/DeviceTaskDataRecord.cpp b/benchmarks/C++/src/richards/DeviceTaskDataRecord.cpp new file mode 100644 index 00000000..a8e4d4ca --- /dev/null +++ b/benchmarks/C++/src/richards/DeviceTaskDataRecord.cpp @@ -0,0 +1,17 @@ +#include "DeviceTaskDataRecord.h" + +using namespace std; + +namespace richards { + + DeviceTaskDataRecord::DeviceTaskDataRecord() { + _pending = NO_WORK; + } + + shared_ptr DeviceTaskDataRecord::getPending() { + return _pending; + } + void DeviceTaskDataRecord::setPending(shared_ptr packet) { + _pending = packet; + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/richards/DeviceTaskDataRecord.h b/benchmarks/C++/src/richards/DeviceTaskDataRecord.h new file mode 100644 index 00000000..8671d55a --- /dev/null +++ b/benchmarks/C++/src/richards/DeviceTaskDataRecord.h @@ -0,0 +1,24 @@ +#ifndef DEVICETASKDATARECORD +#define DEVICETASKDATARECORD + + +#include "Packet.h" +#include +#include + +using namespace std; + +namespace richards { + class DeviceTaskDataRecord : public RBObject { + private: + shared_ptr _pending; + + public: + DeviceTaskDataRecord(); + + shared_ptr getPending(); + void setPending(shared_ptr packet); + }; +} + +#endif //DEVICETASKDATARECORD \ No newline at end of file diff --git a/benchmarks/C++/src/richards/HandlerTaskDataRecord.cpp b/benchmarks/C++/src/richards/HandlerTaskDataRecord.cpp new file mode 100644 index 00000000..b242dd16 --- /dev/null +++ b/benchmarks/C++/src/richards/HandlerTaskDataRecord.cpp @@ -0,0 +1,34 @@ +#include "HandlerTaskDataRecord.h" + +using namespace std; + +namespace richards { + HandlerTaskDataRecord::HandlerTaskDataRecord() { + _workIn = NO_WORK; + _deviceIn = NO_WORK; + } + + shared_ptr HandlerTaskDataRecord::deviceIn() { + return _deviceIn; + } + + void HandlerTaskDataRecord::deviceIn(shared_ptr aPacket) { + _deviceIn = aPacket; + } + + void HandlerTaskDataRecord::deviceInAdd(shared_ptr packet) { + _deviceIn = append(packet, _deviceIn); + } + + shared_ptr HandlerTaskDataRecord::workIn() { + return _workIn; + } + + void HandlerTaskDataRecord::workIn(shared_ptr aWorkQueue) { + _workIn = aWorkQueue; + } + + void HandlerTaskDataRecord::workInAdd(shared_ptr packet) { + _workIn = append(packet, _workIn); + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/richards/HandlerTaskDataRecord.h b/benchmarks/C++/src/richards/HandlerTaskDataRecord.h new file mode 100644 index 00000000..2aa95280 --- /dev/null +++ b/benchmarks/C++/src/richards/HandlerTaskDataRecord.h @@ -0,0 +1,30 @@ +#ifndef HANDLETASKDATARECORD +#define HANDLETASKDATARECORD + +#include "Packet.h" +#include +#include + +using namespace std; + +namespace richards { + class HandlerTaskDataRecord : public RBObject { + private: + + shared_ptr _workIn; + shared_ptr _deviceIn; + + public: + + HandlerTaskDataRecord(); + + shared_ptr deviceIn(); + void deviceIn(shared_ptr aPacket); + void deviceInAdd(shared_ptr packet); + shared_ptr workIn(); + void workIn(shared_ptr aWorkQueue); + void workInAdd(shared_ptr packet); + }; +} + +#endif //HANDLETASKDATARECORD \ No newline at end of file diff --git a/benchmarks/C++/src/richards/IdleTaskDataRecord.cpp b/benchmarks/C++/src/richards/IdleTaskDataRecord.cpp new file mode 100644 index 00000000..6c9ca80a --- /dev/null +++ b/benchmarks/C++/src/richards/IdleTaskDataRecord.cpp @@ -0,0 +1,25 @@ +#include "IdleTaskDataRecord.h" + +namespace richards { + IdleTaskDataRecord::IdleTaskDataRecord() { + _control = 1; + _count = 10000; + } + + int IdleTaskDataRecord::getControl() const { + return _control; + } + + void IdleTaskDataRecord::setControl(int aNumber) { + _control = aNumber; + } + + int IdleTaskDataRecord::getCount() const { + return _count; + } + + void IdleTaskDataRecord::setCount(int aCount) { + _count = aCount; + } +} + diff --git a/benchmarks/C++/src/richards/IdleTaskDataRecord.h b/benchmarks/C++/src/richards/IdleTaskDataRecord.h new file mode 100644 index 00000000..26a1d9e8 --- /dev/null +++ b/benchmarks/C++/src/richards/IdleTaskDataRecord.h @@ -0,0 +1,23 @@ +#ifndef IDLETASKDATARECORD +#define IDLETASKDATARECORD + +#include "RBObject.h" + +namespace richards { + class IdleTaskDataRecord : public RBObject { + private: + + int _control; + int _count; + + public: + IdleTaskDataRecord(); + + int getControl() const; + void setControl(int aNumber); + int getCount() const; + void setCount(int aCount); + }; +} + +#endif //IDLETASKDATARECORD \ No newline at end of file diff --git a/benchmarks/C++/src/richards/Packet.cpp b/benchmarks/C++/src/richards/Packet.cpp new file mode 100644 index 00000000..e2956c85 --- /dev/null +++ b/benchmarks/C++/src/richards/Packet.cpp @@ -0,0 +1,50 @@ +#include "Packet.h" +#include + + +namespace richards { + Packet::Packet(shared_ptr link, int identity, int kind) { + _link = link; + _identity = identity; + _kind = kind; + _datum = 0; + _data = new int[DATA_SIZE]; + } + + int* Packet::getData() { + return _data; + } + + int Packet::getDatum() const { + return _datum; + } + + void Packet::setDatum(int someData) { + _datum = someData; + } + + + int Packet::getIdentity() const { + return _identity; + } + + void Packet::setIdentity(int anIdentity) { + _identity = anIdentity; + } + + int Packet::getKind() const { + return _kind; + } + + shared_ptr Packet::getLink() { + return _link; + } + + void Packet::setLink(shared_ptr aLink) { + _link = aLink; + } + + string Packet::toString() const { + return "Packet id: " + to_string(_identity) + " kind: " + to_string(_kind); + } +} diff --git a/benchmarks/C++/src/richards/Packet.h b/benchmarks/C++/src/richards/Packet.h new file mode 100644 index 00000000..6df0b744 --- /dev/null +++ b/benchmarks/C++/src/richards/Packet.h @@ -0,0 +1,38 @@ +#ifndef PACKET +#define PACKET + +#include +#include +#include "RBObject.h" + +using namespace std; + +namespace richards { + + class Packet : public RBObject { + private: + shared_ptr _link; + int _identity; + int _kind; + int _datum; + int* _data; + + public: + + Packet(shared_ptr link, int identity, int kind); + + int* getData(); + int getDatum() const; + void setDatum(int someData); + int getIdentity() const; + void setIdentity(int anIdentity); + int getKind() const; + shared_ptr getLink(); + void setLink(shared_ptr aLink); + string toString() const; + + static const int DATA_SIZE = 4; + }; +} + +#endif //PACKET \ No newline at end of file diff --git a/benchmarks/C++/src/richards/RBObject.cpp b/benchmarks/C++/src/richards/RBObject.cpp new file mode 100644 index 00000000..97dbbc88 --- /dev/null +++ b/benchmarks/C++/src/richards/RBObject.cpp @@ -0,0 +1,32 @@ +#include "Packet.h" + + +namespace richards { + + shared_ptr RBObject::NO_WORK = nullptr; + shared_ptr RBObject::NO_TASK = nullptr; + + void RBObject::initializeConstants() { + NO_WORK = nullptr; + NO_TASK = nullptr; + }; + + std::shared_ptr RBObject::append(std::shared_ptr packet, std::shared_ptr queueHead) { + packet->setLink(NO_WORK); + if (NO_WORK == queueHead) { + return packet; + } + + std::shared_ptr mouse = queueHead; + std::shared_ptr link; + while (NO_WORK != (link = mouse->getLink())) { + mouse = link; + } + mouse->setLink(packet); + return queueHead; + } + + RBObject::~RBObject() = default; + +} + diff --git a/benchmarks/C++/src/richards/RBObject.h b/benchmarks/C++/src/richards/RBObject.h new file mode 100644 index 00000000..776de805 --- /dev/null +++ b/benchmarks/C++/src/richards/RBObject.h @@ -0,0 +1,37 @@ + +#ifndef RBOBJECT +#define RBOBJECT + + +#include + +using namespace std; + +namespace richards { + class Packet; + class TaskControlBlock; + + class RBObject { + public: + virtual ~RBObject(); + + shared_ptr append(shared_ptr packet, shared_ptr queueHead); + static void initializeConstants(); + + static const int IDLER = 0; + static const int WORKER = 1; + static const int HANDLER_A = 2; + static const int HANDLER_B = 3; + static const int DEVICE_A = 4; + static const int DEVICE_B = 5; + static const int NUM_TYPES = 6; + + static const int DEVICE_PACKET_KIND = 0; + static const int WORK_PACKET_KIND = 1; + + static shared_ptr NO_WORK; + static shared_ptr NO_TASK; + }; +} + +#endif //RBOBJECT \ No newline at end of file diff --git a/benchmarks/C++/src/richards/Scheduler.cpp b/benchmarks/C++/src/richards/Scheduler.cpp new file mode 100644 index 00000000..9f46255b --- /dev/null +++ b/benchmarks/C++/src/richards/Scheduler.cpp @@ -0,0 +1,241 @@ +#include "Scheduler.h" + +namespace richards { + Scheduler::Scheduler() { + RBObject::initializeConstants(); + // init tracing + _layout = 0; + + // init scheduler + _queuePacketCount = 0; + _holdCount = 0; + _taskTable = new shared_ptr[NUM_TYPES]; + + for (int i = 0; i < NUM_TYPES; i++) { + _taskTable[i] = RBObject::NO_TASK; + } + _taskList = RBObject::NO_TASK; + } + + + void Scheduler::createDevice(int identity, int priority, shared_ptr workPacket, shared_ptr state) { + shared_ptr data = make_shared(); + + createTask(identity, priority, workPacket, state, + [&](shared_ptr workArg, shared_ptr wordArg) -> shared_ptr { + shared_ptr dataRecord = dynamic_pointer_cast(wordArg); + shared_ptr functionWork = workArg; + if (RBObject::NO_WORK == functionWork) { + if (RBObject::NO_WORK == (functionWork = dataRecord->getPending())) { + return markWaiting(); + } else { + dataRecord->setPending(RBObject::NO_WORK); + return queuePacket(functionWork); + } + } else { + dataRecord->setPending(functionWork); + if (TRACING) { + trace(functionWork->getDatum()); + } + return holdSelf(); + } + }, data); + } + + void Scheduler::createHandler(int identity, int priority, + shared_ptr workPaket, shared_ptr state) { + + shared_ptr data = make_shared(); + + createTask(identity, priority, workPaket, state, + [&](shared_ptr work, shared_ptr word) -> shared_ptr { + shared_ptr dataRecord = dynamic_pointer_cast(word); + if (RBObject::NO_WORK != work) { + if (WORK_PACKET_KIND == work->getKind()) { + dataRecord->workInAdd(work); + } else { + dataRecord->deviceInAdd(work); + } + } + + shared_ptr workPacket; + if (RBObject::NO_WORK == (workPacket = dataRecord->workIn())) { + return markWaiting(); + } else { + int count = workPacket->getDatum(); + if (count >= Packet::DATA_SIZE) { + dataRecord->workIn(workPacket->getLink()); + return queuePacket(workPacket); + } else { + shared_ptr devicePacket; + if (RBObject::NO_WORK == (devicePacket = dataRecord->deviceIn())) { + return markWaiting(); + } else { + dataRecord->deviceIn(devicePacket->getLink()); + devicePacket->setDatum(workPacket->getData()[count]); + workPacket->setDatum(count + 1); + return queuePacket(devicePacket); + } + } + } + }, data); + } + + void Scheduler::createIdler(int identity, int priority, shared_ptr work, + shared_ptr state) { + + shared_ptr data = make_shared(); + + createTask(identity, priority, work, state, + [&](shared_ptr workArg, shared_ptr wordArg) -> shared_ptr { + shared_ptr dataRecord = dynamic_pointer_cast(wordArg); + dataRecord->setCount(dataRecord->getCount() - 1); + if (0 == dataRecord->getCount()) { + return holdSelf(); + } else { + if (0 == (dataRecord->getControl() & 1)) { + dataRecord->setControl(dataRecord->getControl() / 2); + return release(DEVICE_A); + } else { + dataRecord->setControl((dataRecord->getControl() / 2) ^ 53256); + return release(DEVICE_B); + } + } + }, data); + } + + shared_ptr Scheduler::createPacket(shared_ptr link, int identity, int kind) { + return make_shared(link, identity, kind); + } + + void Scheduler::createTask(int identity, int priority, + shared_ptr work, shared_ptr state, + function(shared_ptr work, shared_ptr word)> aBlock, + shared_ptr data) { + + shared_ptr t = make_shared(_taskList, identity, + priority, work, state, aBlock, data); + _taskList = t; + _taskTable[identity] = t; + } + + void Scheduler::createWorker(int identity, int priority, + shared_ptr workPaket, shared_ptr state) { + + shared_ptr dataRecord = make_shared(); + + createTask(identity, priority, workPaket, state, + [&](shared_ptr work, shared_ptr word) -> shared_ptr { + shared_ptr data = dynamic_pointer_cast(word); + if (RBObject::NO_WORK == work) { + return markWaiting(); + } else { + data->setDestination((HANDLER_A == data->getDestination()) ? HANDLER_B : HANDLER_A); + work->setIdentity(data->getDestination()); + work->setDatum(0); + for (int i = 0; i < Packet::DATA_SIZE; i++) { + data->setCount(data->getCount() + 1); + if (data->getCount() > 26) { + data->setCount(1); + } + work->getData()[i] = 65 + data->getCount() - 1; + } + return queuePacket(work); + } + }, dataRecord); + } + + bool Scheduler::start() { + shared_ptr workQ; + createIdler(IDLER, 0, RBObject::NO_WORK, TaskState::createRunning()); + workQ = createPacket(RBObject::NO_WORK, WORKER, WORK_PACKET_KIND); + workQ = createPacket(workQ, WORKER, WORK_PACKET_KIND); + + createWorker(WORKER, 1000, workQ, TaskState::createWaitingWithPacket()); + workQ = createPacket(RBObject::NO_WORK, DEVICE_A, DEVICE_PACKET_KIND); + workQ = createPacket(workQ, DEVICE_A, DEVICE_PACKET_KIND); + workQ = createPacket(workQ, DEVICE_A, DEVICE_PACKET_KIND); + + createHandler(HANDLER_A, 2000, workQ, TaskState::createWaitingWithPacket()); + workQ = createPacket(RBObject::NO_WORK, DEVICE_B, DEVICE_PACKET_KIND); + workQ = createPacket(workQ, DEVICE_B, DEVICE_PACKET_KIND); + workQ = createPacket(workQ, DEVICE_B, DEVICE_PACKET_KIND); + + createHandler(HANDLER_B, 3000, workQ, TaskState::createWaitingWithPacket()); + createDevice(DEVICE_A, 4000, RBObject::NO_WORK, TaskState::createWaiting()); + createDevice(DEVICE_B, 5000, RBObject::NO_WORK, TaskState::createWaiting()); + + schedule(); + + return _queuePacketCount == 23246 && _holdCount == 9297; + } + + shared_ptr Scheduler::findTask(int identity) { + shared_ptr t = _taskTable[identity]; + if (RBObject::NO_TASK == t) { + throw Error("findTask failed"); + } + return t; + } + + shared_ptr Scheduler::holdSelf() { + _holdCount = _holdCount + 1; + _currentTask->setTaskHolding(true); + return _currentTask->getLink(); + } + + shared_ptr Scheduler::queuePacket(shared_ptr packet) { + shared_ptr t = findTask(packet->getIdentity()); + if (RBObject::NO_TASK == t) { + return RBObject::NO_TASK; + } + + _queuePacketCount = _queuePacketCount + 1; + + packet->setLink(RBObject::NO_WORK); + packet->setIdentity(_currentTaskIdentity); + return t->addInputAndCheckPriority(packet, _currentTask); + } + + shared_ptr Scheduler::release(int identity) { + shared_ptr t = findTask(identity); + if (RBObject::NO_TASK == t) { + return RBObject::NO_TASK; + } + t->setTaskHolding(false); + if (t->getPriority() > _currentTask->getPriority()) { + return t; + } else { + return _currentTask; + } + } + + void Scheduler::trace(int id) { + _layout = _layout - 1; + if (0 >= _layout) { + cout << endl; + _layout = 50; + } + cout << id << endl; + } + + shared_ptr Scheduler::markWaiting() { + _currentTask->setTaskWaiting(true); + return _currentTask; + } + + void Scheduler::schedule() { + _currentTask = _taskList; + while (RBObject::NO_TASK != _currentTask) { + if (_currentTask->isTaskHoldingOrWaiting()) { + _currentTask = _currentTask->getLink(); + } else { + _currentTaskIdentity = _currentTask->getIdentity(); + if (TRACING) { + trace(_currentTaskIdentity); + } + _currentTask = _currentTask->runTask(); + } + } + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/richards/Scheduler.h b/benchmarks/C++/src/richards/Scheduler.h new file mode 100644 index 00000000..ddb977ed --- /dev/null +++ b/benchmarks/C++/src/richards/Scheduler.h @@ -0,0 +1,56 @@ +#ifndef SCHEDULER +#define SCHEDULER + +#include +#include "DeviceTaskDataRecord.h" +#include "TaskControlBlock.h" +#include "HandlerTaskDataRecord.h" +#include +#include +#include "../som/Error.cpp" +#include "IdleTaskDataRecord.h" +#include "WorkerTaskDataRecord.h" + +namespace richards { + class Scheduler: public RBObject { + private: + + shared_ptr _taskList; + shared_ptr _currentTask; + int _currentTaskIdentity{}; + shared_ptr* _taskTable; + int _queuePacketCount; + int _holdCount; + int _layout; + static const bool TRACING = false; + + public: + + Scheduler(); + + void createDevice(int identity, int priority, shared_ptr workPacket, shared_ptr state) ; + void createHandler(int identity, int priority, + shared_ptr workPaket, shared_ptr state); + + void createIdler(int identity, int priority, shared_ptr work, + shared_ptr state); + shared_ptr createPacket(shared_ptr link, int identity, int kind); + void createTask(int identity, int priority, + shared_ptr work, shared_ptr state, + function(shared_ptr work, shared_ptr word)> aBlock, + shared_ptr data); + + void createWorker(int identity, int priority, + shared_ptr workPaket, shared_ptr state); + bool start(); + shared_ptr findTask(int identity); + shared_ptr holdSelf(); + shared_ptr queuePacket(shared_ptr packet); + shared_ptr release(int identity); + void trace(int id); + shared_ptr markWaiting(); + void schedule(); + }; +} + +#endif //SCHEDULER \ No newline at end of file diff --git a/benchmarks/C++/src/richards/TaskControlBlock.cpp b/benchmarks/C++/src/richards/TaskControlBlock.cpp new file mode 100644 index 00000000..123fb629 --- /dev/null +++ b/benchmarks/C++/src/richards/TaskControlBlock.cpp @@ -0,0 +1,61 @@ +#include "TaskControlBlock.h" + +using namespace std; + +namespace richards { + + TaskControlBlock::TaskControlBlock(shared_ptr aLink, int anIdentity, int aPriority, shared_ptr anInitialWorkQueue, + const shared_ptr& anInitialState, function(shared_ptr work, shared_ptr word)> aBlock, + shared_ptr aPrivateData) { + _link = move(aLink); + _identity = anIdentity; + _priority = aPriority; + _input = move(anInitialWorkQueue); + setPacketPending(anInitialState->isPacketPending()); + setTaskWaiting(anInitialState->isTaskWaiting()); + setTaskHolding(anInitialState->isTaskHolding()); + _function = move(aBlock); + _handle = move(aPrivateData); + } + + int TaskControlBlock::getIdentity() const { + return _identity; + } + + shared_ptr TaskControlBlock::getLink() { + return _link; + } + + int TaskControlBlock::getPriority() const { + return _priority; + } + + shared_ptr TaskControlBlock::addInputAndCheckPriority(shared_ptr packet, shared_ptr oldTask) { + if (NO_WORK == _input) { + _input = packet; + setPacketPending(true); + if (_priority > oldTask->getPriority()) { + return shared_from_this(); + } + } else { + _input = append(packet, _input); + } + return oldTask; + } + + shared_ptr TaskControlBlock::runTask() { + shared_ptr message; + if (isWaitingWithPacket()) { + message = _input; + _input = message->getLink(); + if (NO_WORK == _input) { + running(); + } else { + packetPending(); + } + } else { + message = NO_WORK; + } + return _function(message, _handle); + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/richards/TaskControlBlock.h b/benchmarks/C++/src/richards/TaskControlBlock.h new file mode 100644 index 00000000..5e24659a --- /dev/null +++ b/benchmarks/C++/src/richards/TaskControlBlock.h @@ -0,0 +1,40 @@ +#ifndef TASKCONTROLBLOCK +#define TASKCONTROLBLOCK + +#include "TaskState.h" +#include +#include "Packet.h" +#include +#include +#include +#include + +using namespace std; + +namespace richards { + class TaskControlBlock : public TaskState, public enable_shared_from_this { + private: + + shared_ptr _link; + int _identity; + int _priority; + shared_ptr _input; + function(shared_ptr work, shared_ptr word)> _function; + shared_ptr _handle; + + public: + + TaskControlBlock(shared_ptr aLink, int anIdentity, int aPriority, shared_ptr anInitialWorkQueue, + const shared_ptr& anInitialState, function(shared_ptr work, shared_ptr word)> aBlock, + shared_ptr aPrivateData); + + int getIdentity() const; + shared_ptr getLink(); + int getPriority() const; + shared_ptr addInputAndCheckPriority(shared_ptr packet, shared_ptr oldTask); + shared_ptr runTask(); + }; + +} + +#endif //TASKCONTROLBLOCK \ No newline at end of file diff --git a/benchmarks/C++/src/richards/TaskState.cpp b/benchmarks/C++/src/richards/TaskState.cpp new file mode 100644 index 00000000..1ece62af --- /dev/null +++ b/benchmarks/C++/src/richards/TaskState.cpp @@ -0,0 +1,73 @@ +#include "TaskState.h" + +namespace richards { + bool TaskState::isPacketPending() const { + return _packetPending; + } + + bool TaskState::isTaskHolding() const { + return _taskHolding; + } + + bool TaskState::isTaskWaiting() const { + return _taskWaiting; + } + + void TaskState::setTaskHolding(bool b) { + _taskHolding = b; + } + + void TaskState::setTaskWaiting(bool b) { + _taskWaiting = b; + } + + void TaskState::setPacketPending(bool b) { + _packetPending = b; + } + + void TaskState::packetPending() { + _packetPending = true; + _taskWaiting = false; + _taskHolding = false; + } + + void TaskState::running() { + _packetPending = _taskWaiting = _taskHolding = false; + } + + void TaskState::waiting() { + _packetPending = _taskHolding = false; + _taskWaiting = true; + } + + void TaskState::waitingWithPacket() { + _taskHolding = false; + _taskWaiting = _packetPending = true; + } + + bool TaskState::isTaskHoldingOrWaiting() const { + return _taskHolding || (!_packetPending && _taskWaiting); + } + + bool TaskState::isWaitingWithPacket() const { + return _packetPending && _taskWaiting && !_taskHolding; + } + + std::shared_ptr TaskState::createRunning() { + std::shared_ptr t = std::make_shared(); + t->running(); + return t; + } + + std::shared_ptr TaskState::createWaiting() { + std::shared_ptr t = std::make_shared(); + t->waiting(); + return t; + } + + std::shared_ptr TaskState::createWaitingWithPacket() { + std::shared_ptr t = std::make_shared(); + t->waitingWithPacket(); + return t; + } +}; \ No newline at end of file diff --git a/benchmarks/C++/src/richards/TaskState.h b/benchmarks/C++/src/richards/TaskState.h new file mode 100644 index 00000000..8569ba3c --- /dev/null +++ b/benchmarks/C++/src/richards/TaskState.h @@ -0,0 +1,36 @@ +#ifndef TASKSTATE +#define TASKSTATE + +#include "RBObject.h" + +namespace richards { + class TaskState : public RBObject { + private: + + bool _packetPending; + bool _taskWaiting; + bool _taskHolding; + + public: + + bool isPacketPending() const; + bool isTaskHolding() const; + bool isTaskWaiting() const; + void setTaskHolding(bool b); + void setTaskWaiting(bool b); + void setPacketPending(bool b); + void packetPending(); + void running(); + void waiting(); + void waitingWithPacket(); + bool isTaskHoldingOrWaiting() const; + bool isWaitingWithPacket() const; + + static std::shared_ptr createRunning(); + static std::shared_ptr createWaiting(); + static std::shared_ptr createWaitingWithPacket(); + + }; +} + +#endif //TASKSTATE \ No newline at end of file diff --git a/benchmarks/C++/src/richards/WorkerTaskDataRecord.cpp b/benchmarks/C++/src/richards/WorkerTaskDataRecord.cpp new file mode 100644 index 00000000..09146a5c --- /dev/null +++ b/benchmarks/C++/src/richards/WorkerTaskDataRecord.cpp @@ -0,0 +1,24 @@ +#include "WorkerTaskDataRecord.h" + +namespace richards { + WorkerTaskDataRecord::WorkerTaskDataRecord() { + _destination = HANDLER_A; + _count = 0; + } + + int WorkerTaskDataRecord::getCount() const { + return _count; + } + + void WorkerTaskDataRecord::setCount(int aCount) { + _count = aCount; + } + + int WorkerTaskDataRecord::getDestination() const { + return _destination; + } + + void WorkerTaskDataRecord::setDestination(int aHandler) { + _destination = aHandler; + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/richards/WorkerTaskDataRecord.h b/benchmarks/C++/src/richards/WorkerTaskDataRecord.h new file mode 100644 index 00000000..9416cd36 --- /dev/null +++ b/benchmarks/C++/src/richards/WorkerTaskDataRecord.h @@ -0,0 +1,17 @@ +#include "RBObject.h" + +namespace richards { + class WorkerTaskDataRecord : public RBObject { + private: + int _destination; + int _count; + + public: + WorkerTaskDataRecord(); + + int getCount() const; + void setCount(int aCount); + int getDestination() const; + void setDestination(int aHandler); + }; +} \ No newline at end of file From 5805a3ad38cae8410da6efb88f3caae376f9f5cd Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sat, 6 Jan 2024 22:30:52 +0000 Subject: [PATCH 13/40] [C++] Modernized Richards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - use object_tracker for simple memory management I tried explicitly freeing the memory based on the task list, but couldn’t free all memory, and ran into multiple references to the same object, which would have required additional bookkeeping. Signed-off-by: Stefan Marr --- benchmarks/C++/build.sh | 2 +- benchmarks/C++/src/Richards.cpp | 13 - benchmarks/C++/src/Richards.h | 18 - benchmarks/C++/src/richards.cpp | 16 + benchmarks/C++/src/richards.h | 512 ++++++++++++++++++ .../C++/src/richards/DeviceTaskDataRecord.cpp | 17 - .../C++/src/richards/DeviceTaskDataRecord.h | 24 - .../src/richards/HandlerTaskDataRecord.cpp | 34 -- .../C++/src/richards/HandlerTaskDataRecord.h | 30 - .../C++/src/richards/IdleTaskDataRecord.cpp | 25 - .../C++/src/richards/IdleTaskDataRecord.h | 23 - benchmarks/C++/src/richards/Packet.cpp | 50 -- benchmarks/C++/src/richards/Packet.h | 38 -- benchmarks/C++/src/richards/RBObject.cpp | 32 -- benchmarks/C++/src/richards/RBObject.h | 37 -- benchmarks/C++/src/richards/Scheduler.cpp | 241 --------- benchmarks/C++/src/richards/Scheduler.h | 56 -- .../C++/src/richards/TaskControlBlock.cpp | 61 --- .../C++/src/richards/TaskControlBlock.h | 40 -- benchmarks/C++/src/richards/TaskState.cpp | 73 --- benchmarks/C++/src/richards/TaskState.h | 36 -- .../C++/src/richards/WorkerTaskDataRecord.cpp | 24 - .../C++/src/richards/WorkerTaskDataRecord.h | 17 - benchmarks/C++/src/run.h | 4 + 24 files changed, 533 insertions(+), 890 deletions(-) delete mode 100644 benchmarks/C++/src/Richards.cpp delete mode 100644 benchmarks/C++/src/Richards.h create mode 100644 benchmarks/C++/src/richards.cpp create mode 100644 benchmarks/C++/src/richards.h delete mode 100644 benchmarks/C++/src/richards/DeviceTaskDataRecord.cpp delete mode 100644 benchmarks/C++/src/richards/DeviceTaskDataRecord.h delete mode 100644 benchmarks/C++/src/richards/HandlerTaskDataRecord.cpp delete mode 100644 benchmarks/C++/src/richards/HandlerTaskDataRecord.h delete mode 100644 benchmarks/C++/src/richards/IdleTaskDataRecord.cpp delete mode 100644 benchmarks/C++/src/richards/IdleTaskDataRecord.h delete mode 100644 benchmarks/C++/src/richards/Packet.cpp delete mode 100644 benchmarks/C++/src/richards/Packet.h delete mode 100644 benchmarks/C++/src/richards/RBObject.cpp delete mode 100644 benchmarks/C++/src/richards/RBObject.h delete mode 100644 benchmarks/C++/src/richards/Scheduler.cpp delete mode 100644 benchmarks/C++/src/richards/Scheduler.h delete mode 100644 benchmarks/C++/src/richards/TaskControlBlock.cpp delete mode 100644 benchmarks/C++/src/richards/TaskControlBlock.h delete mode 100644 benchmarks/C++/src/richards/TaskState.cpp delete mode 100644 benchmarks/C++/src/richards/TaskState.h delete mode 100644 benchmarks/C++/src/richards/WorkerTaskDataRecord.cpp delete mode 100644 benchmarks/C++/src/richards/WorkerTaskDataRecord.h diff --git a/benchmarks/C++/build.sh b/benchmarks/C++/build.sh index de4599a0..0de64738 100755 --- a/benchmarks/C++/build.sh +++ b/benchmarks/C++/build.sh @@ -71,6 +71,6 @@ else SANATIZE='' fi -SRC='src/harness.cpp src/deltablue.cpp src/memory/object_tracker.cpp' +SRC='src/harness.cpp src/deltablue.cpp src/memory/object_tracker.cpp src/richards.cpp' exec $CMD -Wall -Wextra -Wno-unused-private-field $SANATIZE $OPT -ffp-contract=off -std=c++17 $SRC -o harness diff --git a/benchmarks/C++/src/Richards.cpp b/benchmarks/C++/src/Richards.cpp deleted file mode 100644 index 113b5557..00000000 --- a/benchmarks/C++/src/Richards.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "Richards.h" - -namespace richards { - - bool Richards::verifyResult(std::any result) { - bool result_cast = std::any_cast(result); - return result_cast; - } - - std::any Richards::benchmark() { - return (Scheduler()).start(); - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/Richards.h b/benchmarks/C++/src/Richards.h deleted file mode 100644 index ec2fab1f..00000000 --- a/benchmarks/C++/src/Richards.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef RICHARDS -#define RICHARDS - - -#include "Benchmark.h" -#include "richards/Scheduler.h" - -namespace richards { - class Richards : public Benchmark { - - public: - - bool verifyResult(std::any result) override; - std::any benchmark() override; - }; -}; - -#endif // RICHARDS \ No newline at end of file diff --git a/benchmarks/C++/src/richards.cpp b/benchmarks/C++/src/richards.cpp new file mode 100644 index 00000000..eae1a735 --- /dev/null +++ b/benchmarks/C++/src/richards.cpp @@ -0,0 +1,16 @@ +#include "richards.h" + +Packet* RBObject::append(Packet* packet, Packet* queueHead) { + packet->setLink(NO_WORK); + if (NO_WORK == queueHead) { + return packet; + } + + Packet* mouse = queueHead; + Packet* link = NO_WORK; + while (NO_WORK != (link = mouse->getLink())) { + mouse = link; + } + mouse->setLink(packet); + return queueHead; +} diff --git a/benchmarks/C++/src/richards.h b/benchmarks/C++/src/richards.h new file mode 100644 index 00000000..1512de2e --- /dev/null +++ b/benchmarks/C++/src/richards.h @@ -0,0 +1,512 @@ +#pragma once + +#include "benchmark.h" +#include "memory/object_tracker.h" +#include "som/error.h" + +#include +#include +#include + +using std::cout; +using std::endl; + +class Packet; +class TaskControlBlock; + +class RBObject : public TrackedObject { + public: + Packet* append(Packet* packet, Packet* queueHead); + + static const int32_t IDLER = 0; + static const int32_t WORKER = 1; + static const int32_t HANDLER_A = 2; + static const int32_t HANDLER_B = 3; + static const int32_t DEVICE_A = 4; + static const int32_t DEVICE_B = 5; + static const int32_t NUM_TYPES = 6; + + static const int32_t DEVICE_PACKET_KIND = 0; + static const int32_t WORK_PACKET_KIND = 1; + + static constexpr Packet* const NO_WORK = nullptr; + static constexpr TaskControlBlock* const NO_TASK = nullptr; +}; + +class TaskState : public RBObject { + private: + bool _packetPending{false}; + bool _taskWaiting{false}; + bool _taskHolding{false}; + + public: + [[nodiscard]] bool isPacketPending() const { return _packetPending; } + [[nodiscard]] bool isTaskHolding() const { return _taskHolding; } + [[nodiscard]] bool isTaskWaiting() const { return _taskWaiting; } + void setTaskHolding(bool b) { _taskHolding = b; } + void setTaskWaiting(bool b) { _taskWaiting = b; } + void setPacketPending(bool b) { _packetPending = b; } + + void packetPending() { + _packetPending = true; + _taskWaiting = false; + _taskHolding = false; + } + + void running() { _packetPending = _taskWaiting = _taskHolding = false; } + + void waiting() { + _packetPending = _taskHolding = false; + _taskWaiting = true; + } + + void waitingWithPacket() { + _taskHolding = false; + _taskWaiting = _packetPending = true; + } + + [[nodiscard]] bool isTaskHoldingOrWaiting() const { + return _taskHolding || (!_packetPending && _taskWaiting); + } + + [[nodiscard]] bool isWaitingWithPacket() const { + return _packetPending && _taskWaiting && !_taskHolding; + } + + [[nodiscard]] static TaskState* createRunning() { + auto* t = new TaskState(); + t->running(); + return t; + } + + [[nodiscard]] static TaskState* createWaiting() { + auto* t = new TaskState(); + t->waiting(); + return t; + } + + [[nodiscard]] static TaskState* createWaitingWithPacket() { + auto* t = new TaskState(); + t->waitingWithPacket(); + return t; + } +}; + +class DeviceTaskDataRecord : public RBObject { + private: + Packet* _pending{NO_WORK}; + + public: + DeviceTaskDataRecord() = default; + + [[nodiscard]] Packet* getPending() const { return _pending; } + void setPending(Packet* packet) { _pending = packet; } +}; + +class HandlerTaskDataRecord : public RBObject { + private: + Packet* _workIn{NO_WORK}; + Packet* _deviceIn{NO_WORK}; + + public: + HandlerTaskDataRecord() = default; + + Packet* deviceIn() { return _deviceIn; } + void deviceIn(Packet* aPacket) { _deviceIn = aPacket; } + void deviceInAdd(Packet* packet) { _deviceIn = append(packet, _deviceIn); } + + Packet* workIn() { return _workIn; } + void workIn(Packet* aWorkQueue) { _workIn = aWorkQueue; } + void workInAdd(Packet* packet) { _workIn = append(packet, _workIn); } +}; + +class IdleTaskDataRecord : public RBObject { + private: + int32_t _control{1}; + int32_t _count{10000}; + + public: + IdleTaskDataRecord() = default; + + [[nodiscard]] int32_t getControl() const { return _control; } + void setControl(int32_t aNumber) { _control = aNumber; } + [[nodiscard]] int32_t getCount() const { return _count; } + void setCount(int32_t aCount) { _count = aCount; } +}; + +class Packet : public RBObject { + public: + static const int DATA_SIZE = 4; + + private: + Packet* _link; + int32_t _identity; + int32_t _kind; + int32_t _datum{0}; + std::array _data{0}; + + public: + Packet(Packet* link, int32_t identity, int32_t kind) + : _link(link), _identity(identity), _kind(kind) {} + + [[nodiscard]] std::array* getData() { + return &_data; + } + + [[nodiscard]] int32_t getDatum() const { return _datum; } + void setDatum(int32_t someData) { _datum = someData; } + [[nodiscard]] int32_t getIdentity() const { return _identity; } + void setIdentity(int32_t anIdentity) { _identity = anIdentity; } + [[nodiscard]] int32_t getKind() const { return _kind; } + [[nodiscard]] Packet* getLink() { return _link; } + void setLink(Packet* aLink) { _link = aLink; } + + [[nodiscard]] std::string toString() const { + return "Packet id: " + std::to_string(_identity) + + " kind: " + std::to_string(_kind); + } +}; + +class TaskControlBlock : public TaskState { + private: + TaskControlBlock* _link; + int32_t _identity; + int32_t _priority; + Packet* _input; + std::function _function; + RBObject* _handle; + + public: + TaskControlBlock( + TaskControlBlock* aLink, + int32_t anIdentity, + int32_t aPriority, + Packet* anInitialWorkQueue, + TaskState* anInitialState, + std::function aBlock, + RBObject* aPrivateData) + : _link(aLink), + _identity(anIdentity), + _priority(aPriority), + _input(anInitialWorkQueue), + _function(std::move(aBlock)), + _handle(aPrivateData) { + setPacketPending(anInitialState->isPacketPending()); + setTaskWaiting(anInitialState->isTaskWaiting()); + setTaskHolding(anInitialState->isTaskHolding()); + } + + [[nodiscard]] int32_t getIdentity() const { return _identity; } + [[nodiscard]] TaskControlBlock* getLink() { return _link; } + [[nodiscard]] int32_t getPriority() const { return _priority; } + + [[nodiscard]] TaskControlBlock* addInputAndCheckPriority( + Packet* packet, + TaskControlBlock* oldTask) { + if (NO_WORK == _input) { + _input = packet; + setPacketPending(true); + if (_priority > oldTask->getPriority()) { + return this; + } + } else { + _input = append(packet, _input); + } + return oldTask; + } + + [[nodiscard]] TaskControlBlock* runTask() { + Packet* message = NO_WORK; + + if (isWaitingWithPacket()) { + message = _input; + _input = message->getLink(); + if (NO_WORK == _input) { + running(); + } else { + packetPending(); + } + } else { + message = NO_WORK; + } + return _function(message, _handle); + } +}; + +class WorkerTaskDataRecord : public RBObject { + private: + int32_t _destination{RBObject::HANDLER_A}; + int32_t _count{0}; + + public: + WorkerTaskDataRecord() = default; + + [[nodiscard]] int32_t getCount() const { return _count; } + void setCount(int32_t aCount) { _count = aCount; } + [[nodiscard]] int32_t getDestination() const { return _destination; } + void setDestination(int32_t aHandler) { _destination = aHandler; } +}; + +class Scheduler : public RBObject { + private: + TaskControlBlock* _taskList{NO_TASK}; + TaskControlBlock* _currentTask{NO_TASK}; + int32_t _currentTaskIdentity{0}; + std::array _taskTable{NO_TASK}; + int32_t _queuePacketCount{0}; + int32_t _holdCount{0}; + int32_t _layout{0}; + static const bool TRACING = false; + + public: + Scheduler() = default; + + void createDevice(int32_t identity, + int32_t priority, + Packet* workPacket, + TaskState* state) { + auto* data = new DeviceTaskDataRecord(); + + createTask( + identity, priority, workPacket, state, + [this](Packet* workArg, RBObject* wordArg) -> TaskControlBlock* { + auto* dataRecord = dynamic_cast(wordArg); + Packet* functionWork = workArg; + if (RBObject::NO_WORK == functionWork) { + functionWork = dataRecord->getPending(); + if (RBObject::NO_WORK == functionWork) { + return markWaiting(); + } + dataRecord->setPending(RBObject::NO_WORK); + return queuePacket(functionWork); + } + + dataRecord->setPending(functionWork); + if (TRACING) { + trace(functionWork->getDatum()); + } + return holdSelf(); + }, + data); + } + + void createHandler(int32_t identity, + int32_t priority, + Packet* workPaket, + TaskState* state) { + auto* data = new HandlerTaskDataRecord(); + + createTask( + identity, priority, workPaket, state, + [this](Packet* work, RBObject* word) -> TaskControlBlock* { + auto* dataRecord = dynamic_cast(word); + if (RBObject::NO_WORK != work) { + if (WORK_PACKET_KIND == work->getKind()) { + dataRecord->workInAdd(work); + } else { + dataRecord->deviceInAdd(work); + } + } + + Packet* workPacket = dataRecord->workIn(); + if (RBObject::NO_WORK == workPacket) { + return markWaiting(); + } + const int32_t count = workPacket->getDatum(); + if (count >= Packet::DATA_SIZE) { + dataRecord->workIn(workPacket->getLink()); + return queuePacket(workPacket); + } + Packet* devicePacket = dataRecord->deviceIn(); + if (RBObject::NO_WORK == devicePacket) { + return markWaiting(); + } + dataRecord->deviceIn(devicePacket->getLink()); + devicePacket->setDatum(workPacket->getData()->at(count)); + workPacket->setDatum(count + 1); + return queuePacket(devicePacket); + }, + data); + } + + void createIdler(int32_t identity, + int32_t priority, + Packet* work, + TaskState* state) { + auto* data = new IdleTaskDataRecord(); + + createTask( + identity, priority, work, state, + [this](Packet*, RBObject* wordArg) -> TaskControlBlock* { + auto* dataRecord = dynamic_cast(wordArg); + dataRecord->setCount(dataRecord->getCount() - 1); + if (0 == dataRecord->getCount()) { + return holdSelf(); + } + if (0 == (dataRecord->getControl() & 1)) { + dataRecord->setControl(dataRecord->getControl() / 2); + return release(DEVICE_A); + } + dataRecord->setControl((dataRecord->getControl() / 2) ^ 53256); + return release(DEVICE_B); + }, + data); + } + + Packet* createPacket(Packet* link, int32_t identity, int32_t kind) { + return new Packet(link, identity, kind); + } + + void createTask( + int32_t identity, + int32_t priority, + Packet* work, + TaskState* state, + std::function aBlock, + RBObject* data) { + auto* t = new TaskControlBlock(_taskList, identity, priority, work, state, + std::move(aBlock), data); + _taskList = t; + _taskTable.at(identity) = t; + } + + void createWorker(int32_t identity, + int32_t priority, + Packet* workPaket, + TaskState* state) { + auto* dataRecord = new WorkerTaskDataRecord(); + + createTask( + identity, priority, workPaket, state, + [this](Packet* work, RBObject* word) -> TaskControlBlock* { + auto* data = dynamic_cast(word); + if (RBObject::NO_WORK == work) { + return markWaiting(); + } + data->setDestination( + (HANDLER_A == data->getDestination()) ? HANDLER_B : HANDLER_A); + work->setIdentity(data->getDestination()); + work->setDatum(0); + for (int i = 0; i < Packet::DATA_SIZE; i++) { + data->setCount(data->getCount() + 1); + if (data->getCount() > 26) { + data->setCount(1); + } + work->getData()->at(i) = 65 + data->getCount() - 1; + } + return queuePacket(work); + }, + dataRecord); + } + + bool start() { + Packet* workQ = RBObject::NO_WORK; + createIdler(IDLER, 0, RBObject::NO_WORK, TaskState::createRunning()); + + workQ = createPacket(RBObject::NO_WORK, WORKER, WORK_PACKET_KIND); + workQ = createPacket(workQ, WORKER, WORK_PACKET_KIND); + createWorker(WORKER, 1000, workQ, TaskState::createWaitingWithPacket()); + + workQ = createPacket(RBObject::NO_WORK, DEVICE_A, DEVICE_PACKET_KIND); + workQ = createPacket(workQ, DEVICE_A, DEVICE_PACKET_KIND); + workQ = createPacket(workQ, DEVICE_A, DEVICE_PACKET_KIND); + createHandler(HANDLER_A, 2000, workQ, TaskState::createWaitingWithPacket()); + + workQ = createPacket(RBObject::NO_WORK, DEVICE_B, DEVICE_PACKET_KIND); + workQ = createPacket(workQ, DEVICE_B, DEVICE_PACKET_KIND); + workQ = createPacket(workQ, DEVICE_B, DEVICE_PACKET_KIND); + createHandler(HANDLER_B, 3000, workQ, TaskState::createWaitingWithPacket()); + + createDevice(DEVICE_A, 4000, RBObject::NO_WORK, TaskState::createWaiting()); + createDevice(DEVICE_B, 5000, RBObject::NO_WORK, TaskState::createWaiting()); + + schedule(); + + return _queuePacketCount == 23246 && _holdCount == 9297; + } + + TaskControlBlock* findTask(int32_t identity) { + TaskControlBlock* t = _taskTable.at(identity); + if (RBObject::NO_TASK == t) { + throw Error("findTask failed"); + } + return t; + } + + TaskControlBlock* holdSelf() { + _holdCount = _holdCount + 1; + _currentTask->setTaskHolding(true); + return _currentTask->getLink(); + } + + TaskControlBlock* queuePacket(Packet* packet) { + TaskControlBlock* t = findTask(packet->getIdentity()); + if (RBObject::NO_TASK == t) { + return RBObject::NO_TASK; + } + + _queuePacketCount = _queuePacketCount + 1; + + packet->setLink(RBObject::NO_WORK); + packet->setIdentity(_currentTaskIdentity); + return t->addInputAndCheckPriority(packet, _currentTask); + } + + TaskControlBlock* release(int32_t identity) { + TaskControlBlock* t = findTask(identity); + if (RBObject::NO_TASK == t) { + return RBObject::NO_TASK; + } + t->setTaskHolding(false); + if (t->getPriority() > _currentTask->getPriority()) { + return t; + } + return _currentTask; + } + + void trace(int32_t id) { + _layout = _layout - 1; + if (0 >= _layout) { + cout << endl; + _layout = 50; + } + cout << id << endl; + } + + TaskControlBlock* markWaiting() { + _currentTask->setTaskWaiting(true); + return _currentTask; + } + + void schedule() { + _currentTask = _taskList; + while (RBObject::NO_TASK != _currentTask) { + if (_currentTask->isTaskHoldingOrWaiting()) { + _currentTask = _currentTask->getLink(); + } else { + _currentTaskIdentity = _currentTask->getIdentity(); + if (TRACING) { + trace(_currentTaskIdentity); + } + _currentTask = _currentTask->runTask(); + } + } + } +}; + +class Richards : public Benchmark { + public: + bool verify_result(void* result) override { + const bool result_cast = + static_cast(reinterpret_cast(result)); + return result_cast; + } + + void* benchmark() override { + auto* scheduler = new Scheduler(); + const bool result = scheduler->start(); + + ObjectTracker::releaseAll(); + return reinterpret_cast(static_cast(result)); + } +}; diff --git a/benchmarks/C++/src/richards/DeviceTaskDataRecord.cpp b/benchmarks/C++/src/richards/DeviceTaskDataRecord.cpp deleted file mode 100644 index a8e4d4ca..00000000 --- a/benchmarks/C++/src/richards/DeviceTaskDataRecord.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "DeviceTaskDataRecord.h" - -using namespace std; - -namespace richards { - - DeviceTaskDataRecord::DeviceTaskDataRecord() { - _pending = NO_WORK; - } - - shared_ptr DeviceTaskDataRecord::getPending() { - return _pending; - } - void DeviceTaskDataRecord::setPending(shared_ptr packet) { - _pending = packet; - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/richards/DeviceTaskDataRecord.h b/benchmarks/C++/src/richards/DeviceTaskDataRecord.h deleted file mode 100644 index 8671d55a..00000000 --- a/benchmarks/C++/src/richards/DeviceTaskDataRecord.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef DEVICETASKDATARECORD -#define DEVICETASKDATARECORD - - -#include "Packet.h" -#include -#include - -using namespace std; - -namespace richards { - class DeviceTaskDataRecord : public RBObject { - private: - shared_ptr _pending; - - public: - DeviceTaskDataRecord(); - - shared_ptr getPending(); - void setPending(shared_ptr packet); - }; -} - -#endif //DEVICETASKDATARECORD \ No newline at end of file diff --git a/benchmarks/C++/src/richards/HandlerTaskDataRecord.cpp b/benchmarks/C++/src/richards/HandlerTaskDataRecord.cpp deleted file mode 100644 index b242dd16..00000000 --- a/benchmarks/C++/src/richards/HandlerTaskDataRecord.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "HandlerTaskDataRecord.h" - -using namespace std; - -namespace richards { - HandlerTaskDataRecord::HandlerTaskDataRecord() { - _workIn = NO_WORK; - _deviceIn = NO_WORK; - } - - shared_ptr HandlerTaskDataRecord::deviceIn() { - return _deviceIn; - } - - void HandlerTaskDataRecord::deviceIn(shared_ptr aPacket) { - _deviceIn = aPacket; - } - - void HandlerTaskDataRecord::deviceInAdd(shared_ptr packet) { - _deviceIn = append(packet, _deviceIn); - } - - shared_ptr HandlerTaskDataRecord::workIn() { - return _workIn; - } - - void HandlerTaskDataRecord::workIn(shared_ptr aWorkQueue) { - _workIn = aWorkQueue; - } - - void HandlerTaskDataRecord::workInAdd(shared_ptr packet) { - _workIn = append(packet, _workIn); - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/richards/HandlerTaskDataRecord.h b/benchmarks/C++/src/richards/HandlerTaskDataRecord.h deleted file mode 100644 index 2aa95280..00000000 --- a/benchmarks/C++/src/richards/HandlerTaskDataRecord.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef HANDLETASKDATARECORD -#define HANDLETASKDATARECORD - -#include "Packet.h" -#include -#include - -using namespace std; - -namespace richards { - class HandlerTaskDataRecord : public RBObject { - private: - - shared_ptr _workIn; - shared_ptr _deviceIn; - - public: - - HandlerTaskDataRecord(); - - shared_ptr deviceIn(); - void deviceIn(shared_ptr aPacket); - void deviceInAdd(shared_ptr packet); - shared_ptr workIn(); - void workIn(shared_ptr aWorkQueue); - void workInAdd(shared_ptr packet); - }; -} - -#endif //HANDLETASKDATARECORD \ No newline at end of file diff --git a/benchmarks/C++/src/richards/IdleTaskDataRecord.cpp b/benchmarks/C++/src/richards/IdleTaskDataRecord.cpp deleted file mode 100644 index 6c9ca80a..00000000 --- a/benchmarks/C++/src/richards/IdleTaskDataRecord.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "IdleTaskDataRecord.h" - -namespace richards { - IdleTaskDataRecord::IdleTaskDataRecord() { - _control = 1; - _count = 10000; - } - - int IdleTaskDataRecord::getControl() const { - return _control; - } - - void IdleTaskDataRecord::setControl(int aNumber) { - _control = aNumber; - } - - int IdleTaskDataRecord::getCount() const { - return _count; - } - - void IdleTaskDataRecord::setCount(int aCount) { - _count = aCount; - } -} - diff --git a/benchmarks/C++/src/richards/IdleTaskDataRecord.h b/benchmarks/C++/src/richards/IdleTaskDataRecord.h deleted file mode 100644 index 26a1d9e8..00000000 --- a/benchmarks/C++/src/richards/IdleTaskDataRecord.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef IDLETASKDATARECORD -#define IDLETASKDATARECORD - -#include "RBObject.h" - -namespace richards { - class IdleTaskDataRecord : public RBObject { - private: - - int _control; - int _count; - - public: - IdleTaskDataRecord(); - - int getControl() const; - void setControl(int aNumber); - int getCount() const; - void setCount(int aCount); - }; -} - -#endif //IDLETASKDATARECORD \ No newline at end of file diff --git a/benchmarks/C++/src/richards/Packet.cpp b/benchmarks/C++/src/richards/Packet.cpp deleted file mode 100644 index e2956c85..00000000 --- a/benchmarks/C++/src/richards/Packet.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "Packet.h" -#include - - -namespace richards { - Packet::Packet(shared_ptr link, int identity, int kind) { - _link = link; - _identity = identity; - _kind = kind; - _datum = 0; - _data = new int[DATA_SIZE]; - } - - int* Packet::getData() { - return _data; - } - - int Packet::getDatum() const { - return _datum; - } - - void Packet::setDatum(int someData) { - _datum = someData; - } - - - int Packet::getIdentity() const { - return _identity; - } - - void Packet::setIdentity(int anIdentity) { - _identity = anIdentity; - } - - int Packet::getKind() const { - return _kind; - } - - shared_ptr Packet::getLink() { - return _link; - } - - void Packet::setLink(shared_ptr aLink) { - _link = aLink; - } - - string Packet::toString() const { - return "Packet id: " + to_string(_identity) + " kind: " + to_string(_kind); - } -} diff --git a/benchmarks/C++/src/richards/Packet.h b/benchmarks/C++/src/richards/Packet.h deleted file mode 100644 index 6df0b744..00000000 --- a/benchmarks/C++/src/richards/Packet.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef PACKET -#define PACKET - -#include -#include -#include "RBObject.h" - -using namespace std; - -namespace richards { - - class Packet : public RBObject { - private: - shared_ptr _link; - int _identity; - int _kind; - int _datum; - int* _data; - - public: - - Packet(shared_ptr link, int identity, int kind); - - int* getData(); - int getDatum() const; - void setDatum(int someData); - int getIdentity() const; - void setIdentity(int anIdentity); - int getKind() const; - shared_ptr getLink(); - void setLink(shared_ptr aLink); - string toString() const; - - static const int DATA_SIZE = 4; - }; -} - -#endif //PACKET \ No newline at end of file diff --git a/benchmarks/C++/src/richards/RBObject.cpp b/benchmarks/C++/src/richards/RBObject.cpp deleted file mode 100644 index 97dbbc88..00000000 --- a/benchmarks/C++/src/richards/RBObject.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "Packet.h" - - -namespace richards { - - shared_ptr RBObject::NO_WORK = nullptr; - shared_ptr RBObject::NO_TASK = nullptr; - - void RBObject::initializeConstants() { - NO_WORK = nullptr; - NO_TASK = nullptr; - }; - - std::shared_ptr RBObject::append(std::shared_ptr packet, std::shared_ptr queueHead) { - packet->setLink(NO_WORK); - if (NO_WORK == queueHead) { - return packet; - } - - std::shared_ptr mouse = queueHead; - std::shared_ptr link; - while (NO_WORK != (link = mouse->getLink())) { - mouse = link; - } - mouse->setLink(packet); - return queueHead; - } - - RBObject::~RBObject() = default; - -} - diff --git a/benchmarks/C++/src/richards/RBObject.h b/benchmarks/C++/src/richards/RBObject.h deleted file mode 100644 index 776de805..00000000 --- a/benchmarks/C++/src/richards/RBObject.h +++ /dev/null @@ -1,37 +0,0 @@ - -#ifndef RBOBJECT -#define RBOBJECT - - -#include - -using namespace std; - -namespace richards { - class Packet; - class TaskControlBlock; - - class RBObject { - public: - virtual ~RBObject(); - - shared_ptr append(shared_ptr packet, shared_ptr queueHead); - static void initializeConstants(); - - static const int IDLER = 0; - static const int WORKER = 1; - static const int HANDLER_A = 2; - static const int HANDLER_B = 3; - static const int DEVICE_A = 4; - static const int DEVICE_B = 5; - static const int NUM_TYPES = 6; - - static const int DEVICE_PACKET_KIND = 0; - static const int WORK_PACKET_KIND = 1; - - static shared_ptr NO_WORK; - static shared_ptr NO_TASK; - }; -} - -#endif //RBOBJECT \ No newline at end of file diff --git a/benchmarks/C++/src/richards/Scheduler.cpp b/benchmarks/C++/src/richards/Scheduler.cpp deleted file mode 100644 index 9f46255b..00000000 --- a/benchmarks/C++/src/richards/Scheduler.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#include "Scheduler.h" - -namespace richards { - Scheduler::Scheduler() { - RBObject::initializeConstants(); - // init tracing - _layout = 0; - - // init scheduler - _queuePacketCount = 0; - _holdCount = 0; - _taskTable = new shared_ptr[NUM_TYPES]; - - for (int i = 0; i < NUM_TYPES; i++) { - _taskTable[i] = RBObject::NO_TASK; - } - _taskList = RBObject::NO_TASK; - } - - - void Scheduler::createDevice(int identity, int priority, shared_ptr workPacket, shared_ptr state) { - shared_ptr data = make_shared(); - - createTask(identity, priority, workPacket, state, - [&](shared_ptr workArg, shared_ptr wordArg) -> shared_ptr { - shared_ptr dataRecord = dynamic_pointer_cast(wordArg); - shared_ptr functionWork = workArg; - if (RBObject::NO_WORK == functionWork) { - if (RBObject::NO_WORK == (functionWork = dataRecord->getPending())) { - return markWaiting(); - } else { - dataRecord->setPending(RBObject::NO_WORK); - return queuePacket(functionWork); - } - } else { - dataRecord->setPending(functionWork); - if (TRACING) { - trace(functionWork->getDatum()); - } - return holdSelf(); - } - }, data); - } - - void Scheduler::createHandler(int identity, int priority, - shared_ptr workPaket, shared_ptr state) { - - shared_ptr data = make_shared(); - - createTask(identity, priority, workPaket, state, - [&](shared_ptr work, shared_ptr word) -> shared_ptr { - shared_ptr dataRecord = dynamic_pointer_cast(word); - if (RBObject::NO_WORK != work) { - if (WORK_PACKET_KIND == work->getKind()) { - dataRecord->workInAdd(work); - } else { - dataRecord->deviceInAdd(work); - } - } - - shared_ptr workPacket; - if (RBObject::NO_WORK == (workPacket = dataRecord->workIn())) { - return markWaiting(); - } else { - int count = workPacket->getDatum(); - if (count >= Packet::DATA_SIZE) { - dataRecord->workIn(workPacket->getLink()); - return queuePacket(workPacket); - } else { - shared_ptr devicePacket; - if (RBObject::NO_WORK == (devicePacket = dataRecord->deviceIn())) { - return markWaiting(); - } else { - dataRecord->deviceIn(devicePacket->getLink()); - devicePacket->setDatum(workPacket->getData()[count]); - workPacket->setDatum(count + 1); - return queuePacket(devicePacket); - } - } - } - }, data); - } - - void Scheduler::createIdler(int identity, int priority, shared_ptr work, - shared_ptr state) { - - shared_ptr data = make_shared(); - - createTask(identity, priority, work, state, - [&](shared_ptr workArg, shared_ptr wordArg) -> shared_ptr { - shared_ptr dataRecord = dynamic_pointer_cast(wordArg); - dataRecord->setCount(dataRecord->getCount() - 1); - if (0 == dataRecord->getCount()) { - return holdSelf(); - } else { - if (0 == (dataRecord->getControl() & 1)) { - dataRecord->setControl(dataRecord->getControl() / 2); - return release(DEVICE_A); - } else { - dataRecord->setControl((dataRecord->getControl() / 2) ^ 53256); - return release(DEVICE_B); - } - } - }, data); - } - - shared_ptr Scheduler::createPacket(shared_ptr link, int identity, int kind) { - return make_shared(link, identity, kind); - } - - void Scheduler::createTask(int identity, int priority, - shared_ptr work, shared_ptr state, - function(shared_ptr work, shared_ptr word)> aBlock, - shared_ptr data) { - - shared_ptr t = make_shared(_taskList, identity, - priority, work, state, aBlock, data); - _taskList = t; - _taskTable[identity] = t; - } - - void Scheduler::createWorker(int identity, int priority, - shared_ptr workPaket, shared_ptr state) { - - shared_ptr dataRecord = make_shared(); - - createTask(identity, priority, workPaket, state, - [&](shared_ptr work, shared_ptr word) -> shared_ptr { - shared_ptr data = dynamic_pointer_cast(word); - if (RBObject::NO_WORK == work) { - return markWaiting(); - } else { - data->setDestination((HANDLER_A == data->getDestination()) ? HANDLER_B : HANDLER_A); - work->setIdentity(data->getDestination()); - work->setDatum(0); - for (int i = 0; i < Packet::DATA_SIZE; i++) { - data->setCount(data->getCount() + 1); - if (data->getCount() > 26) { - data->setCount(1); - } - work->getData()[i] = 65 + data->getCount() - 1; - } - return queuePacket(work); - } - }, dataRecord); - } - - bool Scheduler::start() { - shared_ptr workQ; - createIdler(IDLER, 0, RBObject::NO_WORK, TaskState::createRunning()); - workQ = createPacket(RBObject::NO_WORK, WORKER, WORK_PACKET_KIND); - workQ = createPacket(workQ, WORKER, WORK_PACKET_KIND); - - createWorker(WORKER, 1000, workQ, TaskState::createWaitingWithPacket()); - workQ = createPacket(RBObject::NO_WORK, DEVICE_A, DEVICE_PACKET_KIND); - workQ = createPacket(workQ, DEVICE_A, DEVICE_PACKET_KIND); - workQ = createPacket(workQ, DEVICE_A, DEVICE_PACKET_KIND); - - createHandler(HANDLER_A, 2000, workQ, TaskState::createWaitingWithPacket()); - workQ = createPacket(RBObject::NO_WORK, DEVICE_B, DEVICE_PACKET_KIND); - workQ = createPacket(workQ, DEVICE_B, DEVICE_PACKET_KIND); - workQ = createPacket(workQ, DEVICE_B, DEVICE_PACKET_KIND); - - createHandler(HANDLER_B, 3000, workQ, TaskState::createWaitingWithPacket()); - createDevice(DEVICE_A, 4000, RBObject::NO_WORK, TaskState::createWaiting()); - createDevice(DEVICE_B, 5000, RBObject::NO_WORK, TaskState::createWaiting()); - - schedule(); - - return _queuePacketCount == 23246 && _holdCount == 9297; - } - - shared_ptr Scheduler::findTask(int identity) { - shared_ptr t = _taskTable[identity]; - if (RBObject::NO_TASK == t) { - throw Error("findTask failed"); - } - return t; - } - - shared_ptr Scheduler::holdSelf() { - _holdCount = _holdCount + 1; - _currentTask->setTaskHolding(true); - return _currentTask->getLink(); - } - - shared_ptr Scheduler::queuePacket(shared_ptr packet) { - shared_ptr t = findTask(packet->getIdentity()); - if (RBObject::NO_TASK == t) { - return RBObject::NO_TASK; - } - - _queuePacketCount = _queuePacketCount + 1; - - packet->setLink(RBObject::NO_WORK); - packet->setIdentity(_currentTaskIdentity); - return t->addInputAndCheckPriority(packet, _currentTask); - } - - shared_ptr Scheduler::release(int identity) { - shared_ptr t = findTask(identity); - if (RBObject::NO_TASK == t) { - return RBObject::NO_TASK; - } - t->setTaskHolding(false); - if (t->getPriority() > _currentTask->getPriority()) { - return t; - } else { - return _currentTask; - } - } - - void Scheduler::trace(int id) { - _layout = _layout - 1; - if (0 >= _layout) { - cout << endl; - _layout = 50; - } - cout << id << endl; - } - - shared_ptr Scheduler::markWaiting() { - _currentTask->setTaskWaiting(true); - return _currentTask; - } - - void Scheduler::schedule() { - _currentTask = _taskList; - while (RBObject::NO_TASK != _currentTask) { - if (_currentTask->isTaskHoldingOrWaiting()) { - _currentTask = _currentTask->getLink(); - } else { - _currentTaskIdentity = _currentTask->getIdentity(); - if (TRACING) { - trace(_currentTaskIdentity); - } - _currentTask = _currentTask->runTask(); - } - } - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/richards/Scheduler.h b/benchmarks/C++/src/richards/Scheduler.h deleted file mode 100644 index ddb977ed..00000000 --- a/benchmarks/C++/src/richards/Scheduler.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef SCHEDULER -#define SCHEDULER - -#include -#include "DeviceTaskDataRecord.h" -#include "TaskControlBlock.h" -#include "HandlerTaskDataRecord.h" -#include -#include -#include "../som/Error.cpp" -#include "IdleTaskDataRecord.h" -#include "WorkerTaskDataRecord.h" - -namespace richards { - class Scheduler: public RBObject { - private: - - shared_ptr _taskList; - shared_ptr _currentTask; - int _currentTaskIdentity{}; - shared_ptr* _taskTable; - int _queuePacketCount; - int _holdCount; - int _layout; - static const bool TRACING = false; - - public: - - Scheduler(); - - void createDevice(int identity, int priority, shared_ptr workPacket, shared_ptr state) ; - void createHandler(int identity, int priority, - shared_ptr workPaket, shared_ptr state); - - void createIdler(int identity, int priority, shared_ptr work, - shared_ptr state); - shared_ptr createPacket(shared_ptr link, int identity, int kind); - void createTask(int identity, int priority, - shared_ptr work, shared_ptr state, - function(shared_ptr work, shared_ptr word)> aBlock, - shared_ptr data); - - void createWorker(int identity, int priority, - shared_ptr workPaket, shared_ptr state); - bool start(); - shared_ptr findTask(int identity); - shared_ptr holdSelf(); - shared_ptr queuePacket(shared_ptr packet); - shared_ptr release(int identity); - void trace(int id); - shared_ptr markWaiting(); - void schedule(); - }; -} - -#endif //SCHEDULER \ No newline at end of file diff --git a/benchmarks/C++/src/richards/TaskControlBlock.cpp b/benchmarks/C++/src/richards/TaskControlBlock.cpp deleted file mode 100644 index 123fb629..00000000 --- a/benchmarks/C++/src/richards/TaskControlBlock.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "TaskControlBlock.h" - -using namespace std; - -namespace richards { - - TaskControlBlock::TaskControlBlock(shared_ptr aLink, int anIdentity, int aPriority, shared_ptr anInitialWorkQueue, - const shared_ptr& anInitialState, function(shared_ptr work, shared_ptr word)> aBlock, - shared_ptr aPrivateData) { - _link = move(aLink); - _identity = anIdentity; - _priority = aPriority; - _input = move(anInitialWorkQueue); - setPacketPending(anInitialState->isPacketPending()); - setTaskWaiting(anInitialState->isTaskWaiting()); - setTaskHolding(anInitialState->isTaskHolding()); - _function = move(aBlock); - _handle = move(aPrivateData); - } - - int TaskControlBlock::getIdentity() const { - return _identity; - } - - shared_ptr TaskControlBlock::getLink() { - return _link; - } - - int TaskControlBlock::getPriority() const { - return _priority; - } - - shared_ptr TaskControlBlock::addInputAndCheckPriority(shared_ptr packet, shared_ptr oldTask) { - if (NO_WORK == _input) { - _input = packet; - setPacketPending(true); - if (_priority > oldTask->getPriority()) { - return shared_from_this(); - } - } else { - _input = append(packet, _input); - } - return oldTask; - } - - shared_ptr TaskControlBlock::runTask() { - shared_ptr message; - if (isWaitingWithPacket()) { - message = _input; - _input = message->getLink(); - if (NO_WORK == _input) { - running(); - } else { - packetPending(); - } - } else { - message = NO_WORK; - } - return _function(message, _handle); - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/richards/TaskControlBlock.h b/benchmarks/C++/src/richards/TaskControlBlock.h deleted file mode 100644 index 5e24659a..00000000 --- a/benchmarks/C++/src/richards/TaskControlBlock.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef TASKCONTROLBLOCK -#define TASKCONTROLBLOCK - -#include "TaskState.h" -#include -#include "Packet.h" -#include -#include -#include -#include - -using namespace std; - -namespace richards { - class TaskControlBlock : public TaskState, public enable_shared_from_this { - private: - - shared_ptr _link; - int _identity; - int _priority; - shared_ptr _input; - function(shared_ptr work, shared_ptr word)> _function; - shared_ptr _handle; - - public: - - TaskControlBlock(shared_ptr aLink, int anIdentity, int aPriority, shared_ptr anInitialWorkQueue, - const shared_ptr& anInitialState, function(shared_ptr work, shared_ptr word)> aBlock, - shared_ptr aPrivateData); - - int getIdentity() const; - shared_ptr getLink(); - int getPriority() const; - shared_ptr addInputAndCheckPriority(shared_ptr packet, shared_ptr oldTask); - shared_ptr runTask(); - }; - -} - -#endif //TASKCONTROLBLOCK \ No newline at end of file diff --git a/benchmarks/C++/src/richards/TaskState.cpp b/benchmarks/C++/src/richards/TaskState.cpp deleted file mode 100644 index 1ece62af..00000000 --- a/benchmarks/C++/src/richards/TaskState.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "TaskState.h" - -namespace richards { - bool TaskState::isPacketPending() const { - return _packetPending; - } - - bool TaskState::isTaskHolding() const { - return _taskHolding; - } - - bool TaskState::isTaskWaiting() const { - return _taskWaiting; - } - - void TaskState::setTaskHolding(bool b) { - _taskHolding = b; - } - - void TaskState::setTaskWaiting(bool b) { - _taskWaiting = b; - } - - void TaskState::setPacketPending(bool b) { - _packetPending = b; - } - - void TaskState::packetPending() { - _packetPending = true; - _taskWaiting = false; - _taskHolding = false; - } - - void TaskState::running() { - _packetPending = _taskWaiting = _taskHolding = false; - } - - void TaskState::waiting() { - _packetPending = _taskHolding = false; - _taskWaiting = true; - } - - void TaskState::waitingWithPacket() { - _taskHolding = false; - _taskWaiting = _packetPending = true; - } - - bool TaskState::isTaskHoldingOrWaiting() const { - return _taskHolding || (!_packetPending && _taskWaiting); - } - - bool TaskState::isWaitingWithPacket() const { - return _packetPending && _taskWaiting && !_taskHolding; - } - - std::shared_ptr TaskState::createRunning() { - std::shared_ptr t = std::make_shared(); - t->running(); - return t; - } - - std::shared_ptr TaskState::createWaiting() { - std::shared_ptr t = std::make_shared(); - t->waiting(); - return t; - } - - std::shared_ptr TaskState::createWaitingWithPacket() { - std::shared_ptr t = std::make_shared(); - t->waitingWithPacket(); - return t; - } -}; \ No newline at end of file diff --git a/benchmarks/C++/src/richards/TaskState.h b/benchmarks/C++/src/richards/TaskState.h deleted file mode 100644 index 8569ba3c..00000000 --- a/benchmarks/C++/src/richards/TaskState.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef TASKSTATE -#define TASKSTATE - -#include "RBObject.h" - -namespace richards { - class TaskState : public RBObject { - private: - - bool _packetPending; - bool _taskWaiting; - bool _taskHolding; - - public: - - bool isPacketPending() const; - bool isTaskHolding() const; - bool isTaskWaiting() const; - void setTaskHolding(bool b); - void setTaskWaiting(bool b); - void setPacketPending(bool b); - void packetPending(); - void running(); - void waiting(); - void waitingWithPacket(); - bool isTaskHoldingOrWaiting() const; - bool isWaitingWithPacket() const; - - static std::shared_ptr createRunning(); - static std::shared_ptr createWaiting(); - static std::shared_ptr createWaitingWithPacket(); - - }; -} - -#endif //TASKSTATE \ No newline at end of file diff --git a/benchmarks/C++/src/richards/WorkerTaskDataRecord.cpp b/benchmarks/C++/src/richards/WorkerTaskDataRecord.cpp deleted file mode 100644 index 09146a5c..00000000 --- a/benchmarks/C++/src/richards/WorkerTaskDataRecord.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "WorkerTaskDataRecord.h" - -namespace richards { - WorkerTaskDataRecord::WorkerTaskDataRecord() { - _destination = HANDLER_A; - _count = 0; - } - - int WorkerTaskDataRecord::getCount() const { - return _count; - } - - void WorkerTaskDataRecord::setCount(int aCount) { - _count = aCount; - } - - int WorkerTaskDataRecord::getDestination() const { - return _destination; - } - - void WorkerTaskDataRecord::setDestination(int aHandler) { - _destination = aHandler; - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/richards/WorkerTaskDataRecord.h b/benchmarks/C++/src/richards/WorkerTaskDataRecord.h deleted file mode 100644 index 9416cd36..00000000 --- a/benchmarks/C++/src/richards/WorkerTaskDataRecord.h +++ /dev/null @@ -1,17 +0,0 @@ -#include "RBObject.h" - -namespace richards { - class WorkerTaskDataRecord : public RBObject { - private: - int _destination; - int _count; - - public: - WorkerTaskDataRecord(); - - int getCount() const; - void setCount(int aCount); - int getDestination() const; - void setDestination(int aHandler); - }; -} \ No newline at end of file diff --git a/benchmarks/C++/src/run.h b/benchmarks/C++/src/run.h index ce5b94b4..eafeda5c 100644 --- a/benchmarks/C++/src/run.h +++ b/benchmarks/C++/src/run.h @@ -11,6 +11,7 @@ #include "nbody.h" #include "permute.h" #include "queens.h" +#include "richards.h" #include "sieve.h" #include "storage.h" #include "towers.h" @@ -73,6 +74,9 @@ class Run { if (name == "Queens") { return []() -> Benchmark* { return new Queens(); }; } + if (name == "Richards") { + return []() -> Benchmark* { return new Richards(); }; + } if (name == "Sieve") { return []() -> Benchmark* { return new Sieve(); }; } From d9f4451a91ab48e339ba285776f7d75a492ff479 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 7 Jan 2024 13:21:51 +0000 Subject: [PATCH 14/40] [C++] Added CD port by Hugo Jenningros Signed-off-by: Stefan Marr --- benchmarks/C++/src/CD.cpp | 62 +++ benchmarks/C++/src/CD.h | 19 + benchmarks/C++/src/CD/Aircraft.cpp | 10 + benchmarks/C++/src/CD/Aircraft.h | 19 + benchmarks/C++/src/CD/CallSign.cpp | 11 + benchmarks/C++/src/CD/CallSign.h | 18 + benchmarks/C++/src/CD/Collision.cpp | 13 + benchmarks/C++/src/CD/Collision.h | 23 + benchmarks/C++/src/CD/CollisionDetector.cpp | 210 ++++++++ benchmarks/C++/src/CD/CollisionDetector.h | 49 ++ benchmarks/C++/src/CD/Constants.h | 18 + benchmarks/C++/src/CD/Motion.cpp | 114 +++++ benchmarks/C++/src/CD/Motion.h | 29 ++ benchmarks/C++/src/CD/RedBlackTree.cpp | 511 ++++++++++++++++++++ benchmarks/C++/src/CD/Simulator.cpp | 29 ++ benchmarks/C++/src/CD/Simulator.h | 22 + benchmarks/C++/src/CD/Vector2D.cpp | 44 ++ benchmarks/C++/src/CD/Vector2D.h | 24 + benchmarks/C++/src/CD/Vector3D.cpp | 35 ++ benchmarks/C++/src/CD/Vector3D.h | 27 ++ 20 files changed, 1287 insertions(+) create mode 100644 benchmarks/C++/src/CD.cpp create mode 100644 benchmarks/C++/src/CD.h create mode 100644 benchmarks/C++/src/CD/Aircraft.cpp create mode 100644 benchmarks/C++/src/CD/Aircraft.h create mode 100644 benchmarks/C++/src/CD/CallSign.cpp create mode 100644 benchmarks/C++/src/CD/CallSign.h create mode 100644 benchmarks/C++/src/CD/Collision.cpp create mode 100644 benchmarks/C++/src/CD/Collision.h create mode 100644 benchmarks/C++/src/CD/CollisionDetector.cpp create mode 100644 benchmarks/C++/src/CD/CollisionDetector.h create mode 100644 benchmarks/C++/src/CD/Constants.h create mode 100644 benchmarks/C++/src/CD/Motion.cpp create mode 100644 benchmarks/C++/src/CD/Motion.h create mode 100644 benchmarks/C++/src/CD/RedBlackTree.cpp create mode 100644 benchmarks/C++/src/CD/Simulator.cpp create mode 100644 benchmarks/C++/src/CD/Simulator.h create mode 100644 benchmarks/C++/src/CD/Vector2D.cpp create mode 100644 benchmarks/C++/src/CD/Vector2D.h create mode 100644 benchmarks/C++/src/CD/Vector3D.cpp create mode 100644 benchmarks/C++/src/CD/Vector3D.h diff --git a/benchmarks/C++/src/CD.cpp b/benchmarks/C++/src/CD.cpp new file mode 100644 index 00000000..ebe0da36 --- /dev/null +++ b/benchmarks/C++/src/CD.cpp @@ -0,0 +1,62 @@ +#include "CD.h" + +namespace CD { +int CD::benchmark(int numAircrafts) { + int numFrames = 200; + + shared_ptr simulator = make_shared(numAircrafts); + shared_ptr detector = make_shared(); + int actualCollisions = 0; + + for (int i = 0; i < numFrames; i++) { + double time = i / 10.0; + shared_ptr>> collisions = + detector->handleNewFrame(simulator->simulate(time)); + actualCollisions += collisions->size(); + } + + return actualCollisions; +} + +bool CD::innerBenchmarkLoop(int innerIterations) { + return verifyResult(benchmark(innerIterations), innerIterations); +} + +bool CD::verifyResult(int actualCollisions, int numAircrafts) { + if (numAircrafts == 1000) { + return actualCollisions == 14484; + } + if (numAircrafts == 500) { + return actualCollisions == 14484; + } + if (numAircrafts == 250) { + return actualCollisions == 10830; + } + if (numAircrafts == 200) { + return actualCollisions == 8655; + } + if (numAircrafts == 100) { + return actualCollisions == 4305; + } + if (numAircrafts == 10) { + return actualCollisions == 390; + } + if (numAircrafts == 2) { + return actualCollisions == 42; + } + + std::cout << "No verification result for " << numAircrafts << " found" + << std::endl; + std::cout << "Result is: " << actualCollisions << std::endl; + return false; +} + +std::any CD::benchmark() { + throw Error("Should never be reached"); +} + +bool CD::verifyResult(std::any result) { + (void)result; + throw Error("Should never be reached"); +} +}; // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD.h b/benchmarks/C++/src/CD.h new file mode 100644 index 00000000..37bb9649 --- /dev/null +++ b/benchmarks/C++/src/CD.h @@ -0,0 +1,19 @@ +#include +#include "Benchmark.h" +#include "cd/CollisionDetector.h" +#include "cd/Simulator.h" +#include "som/Error.cpp" + +namespace CD { +class CD : public Benchmark { + private: + static int benchmark(int numAircrafts); + + public: + bool innerBenchmarkLoop(int innerIterations) override; + + static bool verifyResult(int actualCollisions, int numAircrafts); + std::any benchmark() override; + bool verifyResult(std::any result) override; +}; +}; // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Aircraft.cpp b/benchmarks/C++/src/CD/Aircraft.cpp new file mode 100644 index 00000000..78ad427c --- /dev/null +++ b/benchmarks/C++/src/CD/Aircraft.cpp @@ -0,0 +1,10 @@ +#include "Aircraft.h" + +namespace CD { + +Aircraft::Aircraft(shared_ptr callsign, + shared_ptr position) { + _callsign = callsign; + _position = position; +} +}; // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Aircraft.h b/benchmarks/C++/src/CD/Aircraft.h new file mode 100644 index 00000000..5b991c98 --- /dev/null +++ b/benchmarks/C++/src/CD/Aircraft.h @@ -0,0 +1,19 @@ +#ifndef AIRCRAFT +#define AIRCRAFT + +#include +#include "CallSign.h" +#include "Vector3D.h" +using namespace std; + +namespace CD { +class Aircraft { + public: + shared_ptr _callsign; + shared_ptr _position; + + Aircraft(shared_ptr callsign, shared_ptr position); +}; +}; // namespace CD + +#endif // AIRCRAFT \ No newline at end of file diff --git a/benchmarks/C++/src/CD/CallSign.cpp b/benchmarks/C++/src/CD/CallSign.cpp new file mode 100644 index 00000000..e1a13601 --- /dev/null +++ b/benchmarks/C++/src/CD/CallSign.cpp @@ -0,0 +1,11 @@ +#include "CallSign.h" + +namespace CD { +CallSign::CallSign(int value) { + _value = value; +} + +int CallSign::compareTo(shared_ptr other) const { + return (_value == other->_value) ? 0 : ((_value < other->_value) ? -1 : 1); +} +}; // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/CallSign.h b/benchmarks/C++/src/CD/CallSign.h new file mode 100644 index 00000000..c7cc48cc --- /dev/null +++ b/benchmarks/C++/src/CD/CallSign.h @@ -0,0 +1,18 @@ +#ifndef CALLSIGN +#define CALLSIGN + +#include +using namespace std; + +namespace CD { +class CallSign { + private: + int _value; + + public: + CallSign(int value); + int compareTo(shared_ptr other) const; +}; +}; // namespace CD + +#endif // CALLSIGN \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Collision.cpp b/benchmarks/C++/src/CD/Collision.cpp new file mode 100644 index 00000000..edbd537c --- /dev/null +++ b/benchmarks/C++/src/CD/Collision.cpp @@ -0,0 +1,13 @@ +#include "Collision.h" + +using namespace std; + +namespace CD { +Collision::Collision(shared_ptr aircraftA, + shared_ptr aircraftB, + shared_ptr position) { + _aircraftA = aircraftA; + _aircraftB = aircraftB; + _position = position; +} +} // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Collision.h b/benchmarks/C++/src/CD/Collision.h new file mode 100644 index 00000000..183c2831 --- /dev/null +++ b/benchmarks/C++/src/CD/Collision.h @@ -0,0 +1,23 @@ +#ifndef COLLISION +#define COLLISION + +#include +#include "CallSign.h" +#include "Vector3D.h" + +using namespace std; + +namespace CD { +class Collision { + public: + shared_ptr _aircraftA; + shared_ptr _aircraftB; + shared_ptr _position; + + Collision(shared_ptr aircraftA, + shared_ptr aircraftB, + shared_ptr position); +}; +}; // namespace CD + +#endif // COLLISION \ No newline at end of file diff --git a/benchmarks/C++/src/CD/CollisionDetector.cpp b/benchmarks/C++/src/CD/CollisionDetector.cpp new file mode 100644 index 00000000..69b6f80d --- /dev/null +++ b/benchmarks/C++/src/CD/CollisionDetector.cpp @@ -0,0 +1,210 @@ +#include "CollisionDetector.h" + +using namespace std; + +namespace CD { +bool CollisionDetector::isInVoxel(shared_ptr voxel, + shared_ptr motion) { + if (voxel->_x > Constants::MAX_X || voxel->_x < Constants::MIN_X || + voxel->_y > Constants::MAX_Y || voxel->_y < Constants::MIN_Y) + return false; + + shared_ptr init = motion->_posOne; + shared_ptr fin = motion->_posTwo; + + double v_s = Constants::GOOD_VOXEL_SIZE; + double r = Constants::PROXIMITY_RADIUS / 2.0; + + double v_x = voxel->_x; + double x0 = init->_x; + double xv = fin->_x - init->_x; + + double v_y = voxel->_y; + double y0 = init->_y; + double yv = fin->_y - init->_y; + + double low_x = (v_x - r - x0) / xv; + double high_x = (v_x + v_s + r - x0) / xv; + + if (xv < 0.0) { + double tmp = low_x; + low_x = high_x; + high_x = tmp; + } + + double low_y = (v_y - r - y0) / yv; + double high_y = (v_y + v_s + r - y0) / yv; + + if (yv < 0.0) { + double tmp = low_y; + low_y = high_y; + high_y = tmp; + } + + return ( + ((xv == 0.0 && v_x <= x0 + r && x0 - r <= v_x + v_s) /* no motion in x */ + || (low_x <= 1.0 && 1.0 <= high_x) || (low_x <= 0.0 && 0.0 <= high_x) || + (0.0 <= low_x && high_x <= 1.0)) && + ((yv == 0.0 && v_y <= y0 + r && y0 - r <= v_y + v_s) /* no motion in y */ + || ((low_y <= 1.0 && 1.0 <= high_y) || (low_y <= 0.0 && 0.0 <= high_y) || + (0.0 <= low_y && high_y <= 1.0))) && + (xv == 0.0 || yv == 0.0 || /* no motion in x or y or both */ + (low_y <= high_x && high_x <= high_y) || + (low_y <= low_x && low_x <= high_y) || + (low_x <= low_y && high_y <= high_x))); +}; + +void CollisionDetector::putIntoMap( + shared_ptr, + shared_ptr>>>> voxelMap, + shared_ptr voxel, + shared_ptr motion) { + shared_ptr>> array = voxelMap->getPtr(voxel); + if (array == nullptr) { + array = make_shared>>(); + voxelMap->putPtr(voxel, array); + } + array->append(motion); +} + +void CollisionDetector::recurse( + shared_ptr, + shared_ptr>>>> voxelMap, + shared_ptr, bool>> seen, + shared_ptr nextVoxel, + shared_ptr motion) { + if (!isInVoxel(nextVoxel, motion)) { + return; + } + if (seen->put(nextVoxel, true) == true) { + return; + } + putIntoMap(voxelMap, nextVoxel, motion); + + recurse(voxelMap, seen, nextVoxel->minus(_horizontal), motion); + recurse(voxelMap, seen, nextVoxel->plus(_horizontal), motion); + recurse(voxelMap, seen, nextVoxel->minus(_vertical), motion); + recurse(voxelMap, seen, nextVoxel->plus(_vertical), motion); + recurse(voxelMap, seen, nextVoxel->minus(_horizontal)->minus(_vertical), + motion); + recurse(voxelMap, seen, nextVoxel->minus(_horizontal)->plus(_vertical), + motion); + recurse(voxelMap, seen, nextVoxel->plus(_horizontal)->minus(_vertical), + motion); + recurse(voxelMap, seen, nextVoxel->plus(_horizontal)->plus(_vertical), + motion); +} + +shared_ptr>>>> +CollisionDetector::reduceCollisionSet( + shared_ptr>> motions) { + shared_ptr, + shared_ptr>>>> + voxelMap = + make_shared, + shared_ptr>>>>(); + motions->forEach([&](shared_ptr motion) -> void { + drawMotionOnVoxelMap(voxelMap, motion); + }); + + shared_ptr>>>> result = + make_shared>>>>(); + + voxelMap->forEach( + [&result](shared_ptr< + RedBlackTree, + shared_ptr>>>::Entry> e) + -> void { + if (e->_value->size() > 1) { + result->append(e->_value); + } + }); + return result; +} + +shared_ptr CollisionDetector::voxelHash( + shared_ptr position) { + int xDiv = (int)(position->_x / Constants::GOOD_VOXEL_SIZE); + int yDiv = (int)(position->_y / Constants::GOOD_VOXEL_SIZE); + + double x = Constants::GOOD_VOXEL_SIZE * xDiv; + double y = Constants::GOOD_VOXEL_SIZE * yDiv; + + if (position->_x < 0) { + x -= Constants::GOOD_VOXEL_SIZE; + } + if (position->_y < 0) { + y -= Constants::GOOD_VOXEL_SIZE; + } + + return make_shared(x, y); +} + +void CollisionDetector::drawMotionOnVoxelMap( + shared_ptr, + shared_ptr>>>> voxelMap, + shared_ptr motion) { + shared_ptr, bool>> seen = + make_shared, bool>>(); + recurse(voxelMap, seen, voxelHash(motion->_posOne), motion); +} + +CollisionDetector::CollisionDetector() { + _state = + make_shared, shared_ptr>>(); +} + +shared_ptr>> CollisionDetector::handleNewFrame( + shared_ptr>> frame) { + shared_ptr>> motions = + make_shared>>(); + shared_ptr, bool>> seen = + make_shared, bool>>(); + frame->forEach([&](shared_ptr aircraft) -> void { + shared_ptr oldPosition = + _state->putPtr(aircraft->_callsign, aircraft->_position); + shared_ptr newPosition = aircraft->_position; + seen->put(aircraft->_callsign, true); + if (oldPosition == nullptr) { + // Treat newly introduced aircraft as if they were stationary. + oldPosition = newPosition; + } + motions->append( + make_shared(aircraft->_callsign, oldPosition, newPosition)); + }); + + shared_ptr>> toRemove = + make_shared>>(); + _state->forEach( + [&seen, &toRemove]( + shared_ptr, + shared_ptr>::Entry> e) -> void { + if (!seen->get(e->_key)) { + toRemove->append(e->_key); + } + }); + + toRemove->forEach([&](shared_ptr e) -> void { _state->remove(e); }); + + shared_ptr>>>> allReduced = + reduceCollisionSet(motions); + shared_ptr>> collisions = + make_shared>>(); + + allReduced->forEach( + [&](shared_ptr>> reduced) -> void { + for (long unsigned int i = 0; i < reduced->size(); ++i) { + shared_ptr motion1 = reduced->atPtr(i); + for (long unsigned int j = i + 1; j < reduced->size(); ++j) { + shared_ptr motion2 = reduced->atPtr(j); + shared_ptr collision = motion1->findIntersection(motion2); + if (collision != nullptr) { + collisions->append(make_shared( + motion1->_callsign, motion2->_callsign, collision)); + } + } + } + }); + return collisions; +}; +} // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/CollisionDetector.h b/benchmarks/C++/src/CD/CollisionDetector.h new file mode 100644 index 00000000..02dc26b4 --- /dev/null +++ b/benchmarks/C++/src/CD/CollisionDetector.h @@ -0,0 +1,49 @@ +#ifndef COLLISIONDETECTOR +#define COLLISIONDETECTOR + +#include "../som/Vector.cpp" +#include "Aircraft.h" +#include "Collision.h" +#include "Motion.h" +#include "RedBlackTree.cpp" +#include "Vector2D.h" + +using namespace std; + +namespace CD { +class CollisionDetector { + private: + shared_ptr, shared_ptr>> _state; + shared_ptr _horizontal = + make_shared(Constants::GOOD_VOXEL_SIZE, 0.0); + shared_ptr _vertical = + make_shared(0.0, Constants::GOOD_VOXEL_SIZE); + + static bool isInVoxel(shared_ptr voxel, shared_ptr motion); + static void putIntoMap( + shared_ptr, + shared_ptr>>>> voxelMap, + shared_ptr voxel, + shared_ptr motion); + void recurse( + shared_ptr, + shared_ptr>>>> voxelMap, + shared_ptr, bool>> seen, + shared_ptr nextVoxel, + shared_ptr motion); + shared_ptr>>>> reduceCollisionSet( + shared_ptr>> motions); + shared_ptr voxelHash(shared_ptr position); + void drawMotionOnVoxelMap( + shared_ptr, + shared_ptr>>>> voxelMap, + shared_ptr motion); + + public: + CollisionDetector(); + shared_ptr>> handleNewFrame( + shared_ptr>> frame); +}; +}; // namespace CD + +#endif // COLLISIONDETECTOR \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Constants.h b/benchmarks/C++/src/CD/Constants.h new file mode 100644 index 00000000..9e9b9b35 --- /dev/null +++ b/benchmarks/C++/src/CD/Constants.h @@ -0,0 +1,18 @@ +#ifndef CONSTANTS +#define CONSTANTS + +namespace CD { +class Constants { + public: + constexpr static const double MIN_X = 0.0; + constexpr static const double MIN_Y = 0.0; + constexpr static const double MAX_X = 1000.0; + constexpr static const double MAX_Y = 1000.0; + constexpr static const double MIN_Z = 0.0; + constexpr static const double MAX_Z = 10.0; + constexpr static const double PROXIMITY_RADIUS = 1.0; + constexpr static const double GOOD_VOXEL_SIZE = PROXIMITY_RADIUS * 2.0; +}; +}; // namespace CD + +#endif // CONSTANTS \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Motion.cpp b/benchmarks/C++/src/CD/Motion.cpp new file mode 100644 index 00000000..1da377a7 --- /dev/null +++ b/benchmarks/C++/src/CD/Motion.cpp @@ -0,0 +1,114 @@ +#include "Motion.h" + +using namespace std; + +namespace CD { +shared_ptr Motion::delta() const { + return _posTwo->minus(_posOne); +} + +Motion::Motion(shared_ptr callsign, + shared_ptr posOne, + shared_ptr posTwo) { + _callsign = callsign; + _posOne = posOne; + _posTwo = posTwo; +} + +shared_ptr Motion::findIntersection(shared_ptr other) { + shared_ptr init1 = _posOne; + shared_ptr init2 = other->_posOne; + shared_ptr vec1 = delta(); + shared_ptr vec2 = other->delta(); + double radius = Constants::PROXIMITY_RADIUS; + + // this test is not geometrical 3-d intersection test, it takes the fact that + // the aircraft move into account ; so it is more like a 4d test (it assumes + // that both of the aircraft have a constant speed over the tested interval) + + // we thus have two points, each of them moving on its line segment at + // constant speed ; we are looking for times when the distance between these + // two points is smaller than r + + // vec1 is vector of aircraft 1 + // vec2 is vector of aircraft 2 + + // a = (V2 - V1)^T * (V2 - V1) + double a = vec2->minus(vec1)->squaredMagnitude(); + + if (a != 0.0) { + // we are first looking for instances of time when the planes are exactly r + // from each other at least one plane is moving ; if the planes are moving + // in parallel, they do not have constant speed + + // if the planes are moving in parallel, then + // if the faster starts behind the slower, we can have 2, 1, or 0 + // solutions if the faster plane starts in front of the slower, we can + // have 0 or 1 solutions + + // if the planes are not moving in parallel, then + + // point P1 = I1 + vV1 + // point P2 = I2 + vV2 + // - looking for v, such that dist(P1,P2) = || P1 - P2 || = r + + // it follows that || P1 - P2 || = sqrt( < P1-P2, P1-P2 > ) + // 0 = -r^2 + < P1 - P2, P1 - P2 > + // from properties of dot product + // 0 = -r^2 + + v * 2 + v^2 * + // so we calculate a, b, c - and solve the quadratic equation + // 0 = c + bv + av^2 + + // b = 2 * + double b = 2.0 * init1->minus(init2)->dot(vec1->minus(vec2)); + + // c = -r^2 + (I2 - I1)^T * (I2 - I1) + double c = -radius * radius + init2->minus(init1)->squaredMagnitude(); + + double discr = b * b - 4.0 * a * c; + if (discr < 0.0) { + return nullptr; + } + + double v1 = (-b - sqrt(discr)) / (2.0 * a); + double v2 = (-b + sqrt(discr)) / (2.0 * a); + + if (v1 <= v2 && ((v1 <= 1.0 && 1.0 <= v2) || (v1 <= 0.0 && 0.0 <= v2) || + (0.0 <= v1 && v2 <= 1.0))) { + // Pick a good "time" at which to report the collision. + double v; + if (v1 <= 0.0) { + // The collision started before this frame. Report it at the start of + // the frame. + v = 0.0; + } else { + // The collision started during this frame. Report it at that moment. + v = v1; + } + + shared_ptr result1 = init1->plus(vec1->times(v)); + shared_ptr result2 = init2->plus(vec2->times(v)); + + shared_ptr result = result1->plus(result2)->times(0.5); + if (result->_x >= Constants::MIN_X && result->_x <= Constants::MAX_X && + result->_y >= Constants::MIN_Y && result->_y <= Constants::MAX_Y && + result->_z >= Constants::MIN_Z && result->_z <= Constants::MAX_Z) { + return result; + } + } + + return nullptr; + } + // the planes have the same speeds and are moving in parallel (or they are not + // moving at all) they thus have the same distance all the time ; we + // calculate it from the initial point + + // dist = || i2 - i1 || = sqrt( ( i2 - i1 )^T * ( i2 - i1 ) ) + double dist = init2->minus(init1)->magnitude(); + if (dist <= radius) { + return init1->plus(init2)->times(0.5); + } + + return nullptr; +} +} // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Motion.h b/benchmarks/C++/src/CD/Motion.h new file mode 100644 index 00000000..86d50dd4 --- /dev/null +++ b/benchmarks/C++/src/CD/Motion.h @@ -0,0 +1,29 @@ +#ifndef MOTION +#define MOTION + +#include +#include "CallSign.h" +#include "Constants.h" +#include "Vector3D.h" + +using namespace std; + +namespace CD { +class Motion { + private: + shared_ptr delta() const; + + public: + shared_ptr _callsign; + shared_ptr _posOne; + shared_ptr _posTwo; + + Motion(shared_ptr callsign, + shared_ptr posOne, + shared_ptr posTwo); + + shared_ptr findIntersection(shared_ptr other); +}; +} // namespace CD + +#endif // MOTION \ No newline at end of file diff --git a/benchmarks/C++/src/CD/RedBlackTree.cpp b/benchmarks/C++/src/CD/RedBlackTree.cpp new file mode 100644 index 00000000..07834a5a --- /dev/null +++ b/benchmarks/C++/src/CD/RedBlackTree.cpp @@ -0,0 +1,511 @@ +#include +#include +#include + +using namespace std; + +namespace CD { + +template +class RedBlackTree { + private: + enum Color { RED = 0, BLACK = 1 }; + + class Node : public enable_shared_from_this { + public: + // Moved to public + K _key; + V _value; + shared_ptr _left; + shared_ptr _right; + shared_ptr _parent; + Color _color; + + shared_ptr successor(void) { + shared_ptr x = this->shared_from_this(); + if (x->_right != nullptr) { + return treeMinimum(x->_right); + } + shared_ptr y = x->_parent; + while (y != nullptr && x == y->_right) { + x = y; + y = y->_parent; + } + return y; + } + + // Moved to public + + Node(K key, V value) { + _key = key; + _value = value; + _left = nullptr; + _right = nullptr; + _left = nullptr; + _parent = nullptr; + _color = RED; + } + }; + + class InsertResult { + public: + bool _isNewEntry; + shared_ptr _newNode; + V _oldValue; + + InsertResult(bool isNewEntry, shared_ptr newNode, V oldValue) { + _isNewEntry = isNewEntry; + _newNode = newNode; + _oldValue = oldValue; + } + }; + + shared_ptr _root; + + static shared_ptr treeMinimum(shared_ptr x) { + shared_ptr current = x; + while (current->_left != nullptr) { + current = current->_left; + } + return current; + } + + shared_ptr treeInsertPtr(K key, V value) { + shared_ptr y = nullptr; + shared_ptr x = _root; + + while (x != nullptr) { + y = x; + + int comparisonResult = key->compareTo(x->_key); + if (comparisonResult < 0) { + x = x->_left; + } else if (comparisonResult > 0) { + x = x->_right; + } else { + V oldValue = x->_value; + x->_value = value; + return make_shared(false, nullptr, oldValue); + } + } + + shared_ptr z = make_shared(key, value); + z->_parent = y; + if (y == nullptr) { + _root = z; + } else { + if (key->compareTo(y->_key) < 0) { + y->_left = z; + } else { + y->_right = z; + } + } + return make_shared(true, z, nullptr); + } + + shared_ptr treeInsert(K key, V value) { + shared_ptr y = nullptr; + shared_ptr x = _root; + + while (x != nullptr) { + y = x; + int comparisonResult = key->compareTo(x->_key); + if (comparisonResult < 0) { + x = x->_left; + } else if (comparisonResult > 0) { + x = x->_right; + } else { + V oldValue = x->_value; + x->_value = value; + return make_shared(false, nullptr, oldValue); + } + } + + shared_ptr z = make_shared(key, value); + z->_parent = y; + if (y == nullptr) { + _root = z; + } else { + if (key->compareTo(y->_key) < 0) { + y->_left = z; + } else { + y->_right = z; + } + } + return make_shared(true, z, V()); + } + + shared_ptr leftRotate(shared_ptr x) { + shared_ptr y = x->_right; + + // Turn y's left subtree into x's right subtree. + x->_right = y->_left; + if (y->_left != nullptr) { + y->_left->_parent = x; + } + + // Link x's parent to y + y->_parent = x->_parent; + if (x->_parent == nullptr) { + _root = y; + } else { + if (x == x->_parent->_left) { + x->_parent->_left = y; + } else { + x->_parent->_right = y; + } + } + + // Put x on y's left. + y->_left = x; + x->_parent = y; + + return y; + } + + shared_ptr rightRotate(shared_ptr y) { + shared_ptr x = y->_left; + + // Turn x's right subtree into y's left subtree. + y->_left = x->_right; + if (x->_right != nullptr) { + x->_right->_parent = y; + } + + // Link y's parent to x; + x->_parent = y->_parent; + if (y->_parent == nullptr) { + _root = x; + } else { + if (y == y->_parent->_left) { + y->_parent->_left = x; + } else { + y->_parent->_right = x; + } + } + + x->_right = y; + y->_parent = x; + + return x; + } + + void removeFixup(shared_ptr x, shared_ptr xParent) { + while (x != _root && (x == nullptr || x->_color == BLACK)) { + if (x == xParent->_left) { + // Note: the text points out that w cannot be null-> The reason is not + // obvious from simply looking at the code; it comes about from the + // properties of the red-black tree. + shared_ptr w = xParent->_right; + if (w->_color == RED) { + // Case 1 + w->_color = BLACK; + xParent->_color = RED; + leftRotate(xParent); + w = xParent->_right; + } + if ((w->_left == nullptr || w->_left->_color == BLACK) && + (w->_right == nullptr || w->_right->_color == BLACK)) { + // Case 2 + w->_color = RED; + x = xParent; + xParent = x->_parent; + } else { + if (w->_right == nullptr || w->_right->_color == BLACK) { + // Case 3 + w->_left->_color = BLACK; + w->_color = RED; + rightRotate(w); + w = xParent->_right; + } + // Case 4 + w->_color = xParent->_color; + xParent->_color = BLACK; + if (w->_right != nullptr) { + w->_right->_color = BLACK; + } + leftRotate(xParent); + x = _root; + xParent = x->_parent; + } + } else { + // Same as "then" clause with "right" and "left" exchanged. + shared_ptr w = xParent->_left; + if (w->_color == RED) { + // Case 1 + w->_color = BLACK; + xParent->_color = RED; + rightRotate(xParent); + w = xParent->_left; + } + if ((w->_right == nullptr || w->_right->_color == BLACK) && + (w->_left == nullptr || w->_left->_color == BLACK)) { + // Case 2 + w->_color = RED; + x = xParent; + xParent = x->_parent; + } else { + if (w->_left == nullptr || w->_left->_color == BLACK) { + // Case 3 + w->_right->_color = BLACK; + w->_color = RED; + leftRotate(w); + w = xParent->_left; + } + // Case 4 + w->_color = xParent->_color; + xParent->_color = BLACK; + if (w->_left != nullptr) { + w->_left->_color = BLACK; + } + rightRotate(xParent); + x = _root; + xParent = x->_parent; + } + } + } + if (x != nullptr) { + x->_color = BLACK; + } + } + + public: + // moved public + class Entry { + public: + K _key; + V _value; + + Entry(K key, V value) { + _key = key; + _value = value; + } + }; + // moved public + + RedBlackTree() { _root = nullptr; }; + + V putPtr(K key, V value) { + shared_ptr insertionResult = treeInsertPtr(key, value); + + if (!insertionResult->_isNewEntry) { + return insertionResult->_oldValue; + } + shared_ptr x = insertionResult->_newNode; + + while (x != _root && x->_parent->_color == RED) { + if (x->_parent == x->_parent->_parent->_left) { + shared_ptr y = x->_parent->_parent->_right; + if (y != nullptr && y->_color == RED) { + // Case 1 + x->_parent->_color = BLACK; + y->_color = BLACK; + x->_parent->_parent->_color = RED; + x = x->_parent->_parent; + } else { + if (x == x->_parent->_right) { + // Case 2 + x = x->_parent; + leftRotate(x); + } + // Case 3 + x->_parent->_color = BLACK; + x->_parent->_parent->_color = RED; + rightRotate(x->_parent->_parent); + } + } else { + // Same as "then" clause with "right" and "left" exchanged. + shared_ptr y = x->_parent->_parent->_left; + if (y != nullptr && y->_color == RED) { + // Case 1 + x->_parent->_color = BLACK; + y->_color = BLACK; + x->_parent->_parent->_color = RED; + x = x->_parent->_parent; + } else { + if (x == x->_parent->_left) { + // Case 2 + x = x->_parent; + rightRotate(x); + } + // Case 3 + x->_parent->_color = BLACK; + x->_parent->_parent->_color = RED; + leftRotate(x->_parent->_parent); + } + } + } + _root->_color = BLACK; + return nullptr; + } + + V put(K key, V value) { + shared_ptr insertionResult = treeInsert(key, value); + + if (!insertionResult->_isNewEntry) { + return insertionResult->_oldValue; + } + shared_ptr x = insertionResult->_newNode; + + while (x != _root && x->_parent->_color == RED) { + if (x->_parent == x->_parent->_parent->_left) { + shared_ptr y = x->_parent->_parent->_right; + if (y != nullptr && y->_color == RED) { + // Case 1 + x->_parent->_color = BLACK; + y->_color = BLACK; + x->_parent->_parent->_color = RED; + x = x->_parent->_parent; + } else { + if (x == x->_parent->_right) { + // Case 2 + x = x->_parent; + leftRotate(x); + } + // Case 3 + x->_parent->_color = BLACK; + x->_parent->_parent->_color = RED; + rightRotate(x->_parent->_parent); + } + } else { + // Same as "then" clause with "right" and "left" exchanged. + shared_ptr y = x->_parent->_parent->_left; + if (y != nullptr && y->_color == RED) { + // Case 1 + x->_parent->_color = BLACK; + y->_color = BLACK; + x->_parent->_parent->_color = RED; + x = x->_parent->_parent; + } else { + if (x == x->_parent->_left) { + // Case 2 + x = x->_parent; + rightRotate(x); + } + // Case 3 + x->_parent->_color = BLACK; + x->_parent->_parent->_color = RED; + leftRotate(x->_parent->_parent); + } + } + } + _root->_color = BLACK; + return V(); + } + + V remove(K key) { + shared_ptr z = findNode(key); + if (z == nullptr) { + return nullptr; + } + + // Y is the node to be unlinked from the tree. + shared_ptr y; + if (z->_left == nullptr || z->_right == nullptr) { + y = z; + } else { + y = z->successor(); + } + + // Y is guaranteed to be non-null at this point. + shared_ptr x; + if (y->_left != nullptr) { + x = y->_left; + } else { + x = y->_right; + } + // X is the child of y which might potentially replace y in the tree. X + // might be null at this point. + shared_ptr xParent; + if (x != nullptr) { + x->_parent = y->_parent; + xParent = x->_parent; + } else { + xParent = y->_parent; + } + if (y->_parent == nullptr) { + _root = x; + } else { + if (y == y->_parent->_left) { + y->_parent->_left = x; + } else { + y->_parent->_right = x; + } + } + + if (y != z) { + if (y->_color == BLACK) { + removeFixup(x, xParent); + } + + y->_parent = z->_parent; + y->_color = z->_color; + y->_left = z->_left; + y->_right = z->_right; + + if (z->_left != nullptr) { + z->_left->_parent = y; + } + if (z->_right != nullptr) { + z->_right->_parent = y; + } + if (z->_parent != nullptr) { + if (z->_parent->_left == z) { + z->_parent->_left = y; + } else { + z->_parent->_right = y; + } + } else { + _root = y; + } + } else if (y->_color == BLACK) { + removeFixup(x, xParent); + } + + return z->_value; + } + + V getPtr(K key) { + shared_ptr node = findNode(key); + if (node == nullptr) { + return nullptr; + } + return node->_value; + } + + V get(K key) { + shared_ptr node = findNode(key); + if (node == nullptr) { + return V(); + } + return node->_value; + } + + void forEach(function)> fn) { + if (_root == nullptr) { + return; + } + shared_ptr current = treeMinimum(_root); + while (current != nullptr) { + fn(make_shared(current->_key, current->_value)); + current = current->successor(); + } + } + + shared_ptr findNode(K key) { + shared_ptr current = _root; + while (current != nullptr) { + int comparisonResult = key->compareTo(current->_key); + if (comparisonResult == 0) { + return current; + } + if (comparisonResult < 0) { + current = current->_left; + } else { + current = current->_right; + } + } + return nullptr; + } +}; +}; // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Simulator.cpp b/benchmarks/C++/src/CD/Simulator.cpp new file mode 100644 index 00000000..4dd16309 --- /dev/null +++ b/benchmarks/C++/src/CD/Simulator.cpp @@ -0,0 +1,29 @@ +#include "Simulator.h" + +using namespace std; + +namespace CD { + +Simulator::Simulator(int numAircraft) { + _aircraft = make_shared>>(); + + for (int i = 0; i < numAircraft; i++) { + _aircraft->append(make_shared(i)); + } +} + +shared_ptr>> Simulator::simulate(double time) { + shared_ptr>> frame = + make_shared>>(); + + for (unsigned long int i = 0; i < _aircraft->size(); i += 2) { + frame->append(make_shared( + _aircraft->atPtr(i), + make_shared(time, cos(time) * 2 + i * 3, 10))); + frame->append(make_shared( + _aircraft->atPtr(i + 1), + make_shared(time, sin(time) * 2 + i * 3, 10))); + } + return frame; +} +}; // namespace CD diff --git a/benchmarks/C++/src/CD/Simulator.h b/benchmarks/C++/src/CD/Simulator.h new file mode 100644 index 00000000..24a6eaef --- /dev/null +++ b/benchmarks/C++/src/CD/Simulator.h @@ -0,0 +1,22 @@ +#ifndef SIMULATOR +#define SIMULATOR + +#include +#include "../som/Vector.cpp" +#include "Aircraft.h" + +using namespace std; + +namespace CD { +class Simulator { + private: + shared_ptr>> _aircraft; + + public: + Simulator(int numAircraft); + + shared_ptr>> simulate(double time); +}; +}; // namespace CD + +#endif // SIMULATOR \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Vector2D.cpp b/benchmarks/C++/src/CD/Vector2D.cpp new file mode 100644 index 00000000..d09a94f5 --- /dev/null +++ b/benchmarks/C++/src/CD/Vector2D.cpp @@ -0,0 +1,44 @@ +#include "Vector2D.h" + +namespace CD { +int Vector2D::compareNumbers(double a, double b) { + if (a == b) { + return 0; + } + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + + // We say that NaN is smaller than non-NaN. + if (a == a) { + return 1; + } + return -1; +} + +Vector2D::Vector2D(double x, double y) { + _x = x; + _y = y; +} + +shared_ptr Vector2D::plus(shared_ptr other) const { + return make_shared(_x + other->_x, _y + other->_y); +} + +shared_ptr Vector2D::minus(shared_ptr other) const { + return make_shared(_x - other->_x, _y - other->_y); +} + +int Vector2D::compareTo(shared_ptr other) { + int result = compareNumbers(_x, other->_x); + + if (result != 0) { + return result; + } + + return compareNumbers(_y, other->_y); +} +} // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Vector2D.h b/benchmarks/C++/src/CD/Vector2D.h new file mode 100644 index 00000000..3bad720d --- /dev/null +++ b/benchmarks/C++/src/CD/Vector2D.h @@ -0,0 +1,24 @@ +#ifndef VECTOR2D +#define VECTOR2D + +#include +using namespace std; + +namespace CD { + +class Vector2D { + private: + static int compareNumbers(double a, double b); + + public: + double _x; + double _y; + + Vector2D(double x, double y); + shared_ptr plus(shared_ptr other) const; + shared_ptr minus(shared_ptr other) const; + int compareTo(shared_ptr other); +}; +} // namespace CD + +#endif // VECTOR2D \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Vector3D.cpp b/benchmarks/C++/src/CD/Vector3D.cpp new file mode 100644 index 00000000..81539ab9 --- /dev/null +++ b/benchmarks/C++/src/CD/Vector3D.cpp @@ -0,0 +1,35 @@ +#include "Vector3D.h" +#include + +namespace CD { + +Vector3D::Vector3D(double x, double y, double z) { + _x = x; + _y = y; + _z = z; +} + +shared_ptr Vector3D::plus(shared_ptr other) const { + return make_shared(_x + other->_x, _y + other->_y, _z + other->_z); +} + +shared_ptr Vector3D::minus(shared_ptr other) const { + return make_shared(_x - other->_x, _y - other->_y, _z - other->_z); +} + +double Vector3D::dot(shared_ptr other) { + return _x * other->_x + _y * other->_y + _z * other->_z; +} + +double Vector3D::squaredMagnitude() { + return dot(shared_from_this()); +} + +double Vector3D::magnitude() { + return sqrt(squaredMagnitude()); +} + +shared_ptr Vector3D::times(double amount) const { + return make_shared(_x * amount, _y * amount, _z * amount); +} +}; // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Vector3D.h b/benchmarks/C++/src/CD/Vector3D.h new file mode 100644 index 00000000..8db8ee3a --- /dev/null +++ b/benchmarks/C++/src/CD/Vector3D.h @@ -0,0 +1,27 @@ +#ifndef VECTOR3D +#define VECTOR3D + +#include +#include +using namespace std; + +namespace CD { + +class Vector3D : public enable_shared_from_this { + public: + double _x; + double _y; + double _z; + + Vector3D(double x, double y, double z); + + shared_ptr plus(shared_ptr other) const; + shared_ptr minus(shared_ptr other) const; + double dot(shared_ptr other); + double squaredMagnitude(); + double magnitude(); + shared_ptr times(double amount) const; +}; +} // namespace CD + +#endif // VECTOR3D \ No newline at end of file From bb23974048581a0f871d08f73d8b357caf8429e9 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 9 Jan 2024 15:15:32 +0000 Subject: [PATCH 15/40] [C++] Modernize CD Signed-off-by: Stefan Marr --- benchmarks/C++/src/CD.cpp | 62 -- benchmarks/C++/src/CD.h | 19 - benchmarks/C++/src/CD/Aircraft.cpp | 10 - benchmarks/C++/src/CD/Aircraft.h | 19 - benchmarks/C++/src/CD/CallSign.cpp | 11 - benchmarks/C++/src/CD/CallSign.h | 18 - benchmarks/C++/src/CD/Collision.cpp | 13 - benchmarks/C++/src/CD/Collision.h | 23 - benchmarks/C++/src/CD/CollisionDetector.cpp | 210 ----- benchmarks/C++/src/CD/CollisionDetector.h | 49 - benchmarks/C++/src/CD/Constants.h | 18 - benchmarks/C++/src/CD/Motion.cpp | 114 --- benchmarks/C++/src/CD/Motion.h | 29 - benchmarks/C++/src/CD/RedBlackTree.cpp | 511 ----------- benchmarks/C++/src/CD/Simulator.cpp | 29 - benchmarks/C++/src/CD/Simulator.h | 22 - benchmarks/C++/src/CD/Vector2D.cpp | 44 - benchmarks/C++/src/CD/Vector2D.h | 24 - benchmarks/C++/src/CD/Vector3D.cpp | 35 - benchmarks/C++/src/CD/Vector3D.h | 27 - benchmarks/C++/src/cd.h | 947 ++++++++++++++++++++ benchmarks/C++/src/json.h | 6 +- benchmarks/C++/src/run.h | 4 + 23 files changed, 954 insertions(+), 1290 deletions(-) delete mode 100644 benchmarks/C++/src/CD.cpp delete mode 100644 benchmarks/C++/src/CD.h delete mode 100644 benchmarks/C++/src/CD/Aircraft.cpp delete mode 100644 benchmarks/C++/src/CD/Aircraft.h delete mode 100644 benchmarks/C++/src/CD/CallSign.cpp delete mode 100644 benchmarks/C++/src/CD/CallSign.h delete mode 100644 benchmarks/C++/src/CD/Collision.cpp delete mode 100644 benchmarks/C++/src/CD/Collision.h delete mode 100644 benchmarks/C++/src/CD/CollisionDetector.cpp delete mode 100644 benchmarks/C++/src/CD/CollisionDetector.h delete mode 100644 benchmarks/C++/src/CD/Constants.h delete mode 100644 benchmarks/C++/src/CD/Motion.cpp delete mode 100644 benchmarks/C++/src/CD/Motion.h delete mode 100644 benchmarks/C++/src/CD/RedBlackTree.cpp delete mode 100644 benchmarks/C++/src/CD/Simulator.cpp delete mode 100644 benchmarks/C++/src/CD/Simulator.h delete mode 100644 benchmarks/C++/src/CD/Vector2D.cpp delete mode 100644 benchmarks/C++/src/CD/Vector2D.h delete mode 100644 benchmarks/C++/src/CD/Vector3D.cpp delete mode 100644 benchmarks/C++/src/CD/Vector3D.h create mode 100644 benchmarks/C++/src/cd.h diff --git a/benchmarks/C++/src/CD.cpp b/benchmarks/C++/src/CD.cpp deleted file mode 100644 index ebe0da36..00000000 --- a/benchmarks/C++/src/CD.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "CD.h" - -namespace CD { -int CD::benchmark(int numAircrafts) { - int numFrames = 200; - - shared_ptr simulator = make_shared(numAircrafts); - shared_ptr detector = make_shared(); - int actualCollisions = 0; - - for (int i = 0; i < numFrames; i++) { - double time = i / 10.0; - shared_ptr>> collisions = - detector->handleNewFrame(simulator->simulate(time)); - actualCollisions += collisions->size(); - } - - return actualCollisions; -} - -bool CD::innerBenchmarkLoop(int innerIterations) { - return verifyResult(benchmark(innerIterations), innerIterations); -} - -bool CD::verifyResult(int actualCollisions, int numAircrafts) { - if (numAircrafts == 1000) { - return actualCollisions == 14484; - } - if (numAircrafts == 500) { - return actualCollisions == 14484; - } - if (numAircrafts == 250) { - return actualCollisions == 10830; - } - if (numAircrafts == 200) { - return actualCollisions == 8655; - } - if (numAircrafts == 100) { - return actualCollisions == 4305; - } - if (numAircrafts == 10) { - return actualCollisions == 390; - } - if (numAircrafts == 2) { - return actualCollisions == 42; - } - - std::cout << "No verification result for " << numAircrafts << " found" - << std::endl; - std::cout << "Result is: " << actualCollisions << std::endl; - return false; -} - -std::any CD::benchmark() { - throw Error("Should never be reached"); -} - -bool CD::verifyResult(std::any result) { - (void)result; - throw Error("Should never be reached"); -} -}; // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD.h b/benchmarks/C++/src/CD.h deleted file mode 100644 index 37bb9649..00000000 --- a/benchmarks/C++/src/CD.h +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include "Benchmark.h" -#include "cd/CollisionDetector.h" -#include "cd/Simulator.h" -#include "som/Error.cpp" - -namespace CD { -class CD : public Benchmark { - private: - static int benchmark(int numAircrafts); - - public: - bool innerBenchmarkLoop(int innerIterations) override; - - static bool verifyResult(int actualCollisions, int numAircrafts); - std::any benchmark() override; - bool verifyResult(std::any result) override; -}; -}; // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Aircraft.cpp b/benchmarks/C++/src/CD/Aircraft.cpp deleted file mode 100644 index 78ad427c..00000000 --- a/benchmarks/C++/src/CD/Aircraft.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "Aircraft.h" - -namespace CD { - -Aircraft::Aircraft(shared_ptr callsign, - shared_ptr position) { - _callsign = callsign; - _position = position; -} -}; // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Aircraft.h b/benchmarks/C++/src/CD/Aircraft.h deleted file mode 100644 index 5b991c98..00000000 --- a/benchmarks/C++/src/CD/Aircraft.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef AIRCRAFT -#define AIRCRAFT - -#include -#include "CallSign.h" -#include "Vector3D.h" -using namespace std; - -namespace CD { -class Aircraft { - public: - shared_ptr _callsign; - shared_ptr _position; - - Aircraft(shared_ptr callsign, shared_ptr position); -}; -}; // namespace CD - -#endif // AIRCRAFT \ No newline at end of file diff --git a/benchmarks/C++/src/CD/CallSign.cpp b/benchmarks/C++/src/CD/CallSign.cpp deleted file mode 100644 index e1a13601..00000000 --- a/benchmarks/C++/src/CD/CallSign.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "CallSign.h" - -namespace CD { -CallSign::CallSign(int value) { - _value = value; -} - -int CallSign::compareTo(shared_ptr other) const { - return (_value == other->_value) ? 0 : ((_value < other->_value) ? -1 : 1); -} -}; // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/CallSign.h b/benchmarks/C++/src/CD/CallSign.h deleted file mode 100644 index c7cc48cc..00000000 --- a/benchmarks/C++/src/CD/CallSign.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CALLSIGN -#define CALLSIGN - -#include -using namespace std; - -namespace CD { -class CallSign { - private: - int _value; - - public: - CallSign(int value); - int compareTo(shared_ptr other) const; -}; -}; // namespace CD - -#endif // CALLSIGN \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Collision.cpp b/benchmarks/C++/src/CD/Collision.cpp deleted file mode 100644 index edbd537c..00000000 --- a/benchmarks/C++/src/CD/Collision.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "Collision.h" - -using namespace std; - -namespace CD { -Collision::Collision(shared_ptr aircraftA, - shared_ptr aircraftB, - shared_ptr position) { - _aircraftA = aircraftA; - _aircraftB = aircraftB; - _position = position; -} -} // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Collision.h b/benchmarks/C++/src/CD/Collision.h deleted file mode 100644 index 183c2831..00000000 --- a/benchmarks/C++/src/CD/Collision.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef COLLISION -#define COLLISION - -#include -#include "CallSign.h" -#include "Vector3D.h" - -using namespace std; - -namespace CD { -class Collision { - public: - shared_ptr _aircraftA; - shared_ptr _aircraftB; - shared_ptr _position; - - Collision(shared_ptr aircraftA, - shared_ptr aircraftB, - shared_ptr position); -}; -}; // namespace CD - -#endif // COLLISION \ No newline at end of file diff --git a/benchmarks/C++/src/CD/CollisionDetector.cpp b/benchmarks/C++/src/CD/CollisionDetector.cpp deleted file mode 100644 index 69b6f80d..00000000 --- a/benchmarks/C++/src/CD/CollisionDetector.cpp +++ /dev/null @@ -1,210 +0,0 @@ -#include "CollisionDetector.h" - -using namespace std; - -namespace CD { -bool CollisionDetector::isInVoxel(shared_ptr voxel, - shared_ptr motion) { - if (voxel->_x > Constants::MAX_X || voxel->_x < Constants::MIN_X || - voxel->_y > Constants::MAX_Y || voxel->_y < Constants::MIN_Y) - return false; - - shared_ptr init = motion->_posOne; - shared_ptr fin = motion->_posTwo; - - double v_s = Constants::GOOD_VOXEL_SIZE; - double r = Constants::PROXIMITY_RADIUS / 2.0; - - double v_x = voxel->_x; - double x0 = init->_x; - double xv = fin->_x - init->_x; - - double v_y = voxel->_y; - double y0 = init->_y; - double yv = fin->_y - init->_y; - - double low_x = (v_x - r - x0) / xv; - double high_x = (v_x + v_s + r - x0) / xv; - - if (xv < 0.0) { - double tmp = low_x; - low_x = high_x; - high_x = tmp; - } - - double low_y = (v_y - r - y0) / yv; - double high_y = (v_y + v_s + r - y0) / yv; - - if (yv < 0.0) { - double tmp = low_y; - low_y = high_y; - high_y = tmp; - } - - return ( - ((xv == 0.0 && v_x <= x0 + r && x0 - r <= v_x + v_s) /* no motion in x */ - || (low_x <= 1.0 && 1.0 <= high_x) || (low_x <= 0.0 && 0.0 <= high_x) || - (0.0 <= low_x && high_x <= 1.0)) && - ((yv == 0.0 && v_y <= y0 + r && y0 - r <= v_y + v_s) /* no motion in y */ - || ((low_y <= 1.0 && 1.0 <= high_y) || (low_y <= 0.0 && 0.0 <= high_y) || - (0.0 <= low_y && high_y <= 1.0))) && - (xv == 0.0 || yv == 0.0 || /* no motion in x or y or both */ - (low_y <= high_x && high_x <= high_y) || - (low_y <= low_x && low_x <= high_y) || - (low_x <= low_y && high_y <= high_x))); -}; - -void CollisionDetector::putIntoMap( - shared_ptr, - shared_ptr>>>> voxelMap, - shared_ptr voxel, - shared_ptr motion) { - shared_ptr>> array = voxelMap->getPtr(voxel); - if (array == nullptr) { - array = make_shared>>(); - voxelMap->putPtr(voxel, array); - } - array->append(motion); -} - -void CollisionDetector::recurse( - shared_ptr, - shared_ptr>>>> voxelMap, - shared_ptr, bool>> seen, - shared_ptr nextVoxel, - shared_ptr motion) { - if (!isInVoxel(nextVoxel, motion)) { - return; - } - if (seen->put(nextVoxel, true) == true) { - return; - } - putIntoMap(voxelMap, nextVoxel, motion); - - recurse(voxelMap, seen, nextVoxel->minus(_horizontal), motion); - recurse(voxelMap, seen, nextVoxel->plus(_horizontal), motion); - recurse(voxelMap, seen, nextVoxel->minus(_vertical), motion); - recurse(voxelMap, seen, nextVoxel->plus(_vertical), motion); - recurse(voxelMap, seen, nextVoxel->minus(_horizontal)->minus(_vertical), - motion); - recurse(voxelMap, seen, nextVoxel->minus(_horizontal)->plus(_vertical), - motion); - recurse(voxelMap, seen, nextVoxel->plus(_horizontal)->minus(_vertical), - motion); - recurse(voxelMap, seen, nextVoxel->plus(_horizontal)->plus(_vertical), - motion); -} - -shared_ptr>>>> -CollisionDetector::reduceCollisionSet( - shared_ptr>> motions) { - shared_ptr, - shared_ptr>>>> - voxelMap = - make_shared, - shared_ptr>>>>(); - motions->forEach([&](shared_ptr motion) -> void { - drawMotionOnVoxelMap(voxelMap, motion); - }); - - shared_ptr>>>> result = - make_shared>>>>(); - - voxelMap->forEach( - [&result](shared_ptr< - RedBlackTree, - shared_ptr>>>::Entry> e) - -> void { - if (e->_value->size() > 1) { - result->append(e->_value); - } - }); - return result; -} - -shared_ptr CollisionDetector::voxelHash( - shared_ptr position) { - int xDiv = (int)(position->_x / Constants::GOOD_VOXEL_SIZE); - int yDiv = (int)(position->_y / Constants::GOOD_VOXEL_SIZE); - - double x = Constants::GOOD_VOXEL_SIZE * xDiv; - double y = Constants::GOOD_VOXEL_SIZE * yDiv; - - if (position->_x < 0) { - x -= Constants::GOOD_VOXEL_SIZE; - } - if (position->_y < 0) { - y -= Constants::GOOD_VOXEL_SIZE; - } - - return make_shared(x, y); -} - -void CollisionDetector::drawMotionOnVoxelMap( - shared_ptr, - shared_ptr>>>> voxelMap, - shared_ptr motion) { - shared_ptr, bool>> seen = - make_shared, bool>>(); - recurse(voxelMap, seen, voxelHash(motion->_posOne), motion); -} - -CollisionDetector::CollisionDetector() { - _state = - make_shared, shared_ptr>>(); -} - -shared_ptr>> CollisionDetector::handleNewFrame( - shared_ptr>> frame) { - shared_ptr>> motions = - make_shared>>(); - shared_ptr, bool>> seen = - make_shared, bool>>(); - frame->forEach([&](shared_ptr aircraft) -> void { - shared_ptr oldPosition = - _state->putPtr(aircraft->_callsign, aircraft->_position); - shared_ptr newPosition = aircraft->_position; - seen->put(aircraft->_callsign, true); - if (oldPosition == nullptr) { - // Treat newly introduced aircraft as if they were stationary. - oldPosition = newPosition; - } - motions->append( - make_shared(aircraft->_callsign, oldPosition, newPosition)); - }); - - shared_ptr>> toRemove = - make_shared>>(); - _state->forEach( - [&seen, &toRemove]( - shared_ptr, - shared_ptr>::Entry> e) -> void { - if (!seen->get(e->_key)) { - toRemove->append(e->_key); - } - }); - - toRemove->forEach([&](shared_ptr e) -> void { _state->remove(e); }); - - shared_ptr>>>> allReduced = - reduceCollisionSet(motions); - shared_ptr>> collisions = - make_shared>>(); - - allReduced->forEach( - [&](shared_ptr>> reduced) -> void { - for (long unsigned int i = 0; i < reduced->size(); ++i) { - shared_ptr motion1 = reduced->atPtr(i); - for (long unsigned int j = i + 1; j < reduced->size(); ++j) { - shared_ptr motion2 = reduced->atPtr(j); - shared_ptr collision = motion1->findIntersection(motion2); - if (collision != nullptr) { - collisions->append(make_shared( - motion1->_callsign, motion2->_callsign, collision)); - } - } - } - }); - return collisions; -}; -} // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/CollisionDetector.h b/benchmarks/C++/src/CD/CollisionDetector.h deleted file mode 100644 index 02dc26b4..00000000 --- a/benchmarks/C++/src/CD/CollisionDetector.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef COLLISIONDETECTOR -#define COLLISIONDETECTOR - -#include "../som/Vector.cpp" -#include "Aircraft.h" -#include "Collision.h" -#include "Motion.h" -#include "RedBlackTree.cpp" -#include "Vector2D.h" - -using namespace std; - -namespace CD { -class CollisionDetector { - private: - shared_ptr, shared_ptr>> _state; - shared_ptr _horizontal = - make_shared(Constants::GOOD_VOXEL_SIZE, 0.0); - shared_ptr _vertical = - make_shared(0.0, Constants::GOOD_VOXEL_SIZE); - - static bool isInVoxel(shared_ptr voxel, shared_ptr motion); - static void putIntoMap( - shared_ptr, - shared_ptr>>>> voxelMap, - shared_ptr voxel, - shared_ptr motion); - void recurse( - shared_ptr, - shared_ptr>>>> voxelMap, - shared_ptr, bool>> seen, - shared_ptr nextVoxel, - shared_ptr motion); - shared_ptr>>>> reduceCollisionSet( - shared_ptr>> motions); - shared_ptr voxelHash(shared_ptr position); - void drawMotionOnVoxelMap( - shared_ptr, - shared_ptr>>>> voxelMap, - shared_ptr motion); - - public: - CollisionDetector(); - shared_ptr>> handleNewFrame( - shared_ptr>> frame); -}; -}; // namespace CD - -#endif // COLLISIONDETECTOR \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Constants.h b/benchmarks/C++/src/CD/Constants.h deleted file mode 100644 index 9e9b9b35..00000000 --- a/benchmarks/C++/src/CD/Constants.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CONSTANTS -#define CONSTANTS - -namespace CD { -class Constants { - public: - constexpr static const double MIN_X = 0.0; - constexpr static const double MIN_Y = 0.0; - constexpr static const double MAX_X = 1000.0; - constexpr static const double MAX_Y = 1000.0; - constexpr static const double MIN_Z = 0.0; - constexpr static const double MAX_Z = 10.0; - constexpr static const double PROXIMITY_RADIUS = 1.0; - constexpr static const double GOOD_VOXEL_SIZE = PROXIMITY_RADIUS * 2.0; -}; -}; // namespace CD - -#endif // CONSTANTS \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Motion.cpp b/benchmarks/C++/src/CD/Motion.cpp deleted file mode 100644 index 1da377a7..00000000 --- a/benchmarks/C++/src/CD/Motion.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "Motion.h" - -using namespace std; - -namespace CD { -shared_ptr Motion::delta() const { - return _posTwo->minus(_posOne); -} - -Motion::Motion(shared_ptr callsign, - shared_ptr posOne, - shared_ptr posTwo) { - _callsign = callsign; - _posOne = posOne; - _posTwo = posTwo; -} - -shared_ptr Motion::findIntersection(shared_ptr other) { - shared_ptr init1 = _posOne; - shared_ptr init2 = other->_posOne; - shared_ptr vec1 = delta(); - shared_ptr vec2 = other->delta(); - double radius = Constants::PROXIMITY_RADIUS; - - // this test is not geometrical 3-d intersection test, it takes the fact that - // the aircraft move into account ; so it is more like a 4d test (it assumes - // that both of the aircraft have a constant speed over the tested interval) - - // we thus have two points, each of them moving on its line segment at - // constant speed ; we are looking for times when the distance between these - // two points is smaller than r - - // vec1 is vector of aircraft 1 - // vec2 is vector of aircraft 2 - - // a = (V2 - V1)^T * (V2 - V1) - double a = vec2->minus(vec1)->squaredMagnitude(); - - if (a != 0.0) { - // we are first looking for instances of time when the planes are exactly r - // from each other at least one plane is moving ; if the planes are moving - // in parallel, they do not have constant speed - - // if the planes are moving in parallel, then - // if the faster starts behind the slower, we can have 2, 1, or 0 - // solutions if the faster plane starts in front of the slower, we can - // have 0 or 1 solutions - - // if the planes are not moving in parallel, then - - // point P1 = I1 + vV1 - // point P2 = I2 + vV2 - // - looking for v, such that dist(P1,P2) = || P1 - P2 || = r - - // it follows that || P1 - P2 || = sqrt( < P1-P2, P1-P2 > ) - // 0 = -r^2 + < P1 - P2, P1 - P2 > - // from properties of dot product - // 0 = -r^2 + + v * 2 + v^2 * - // so we calculate a, b, c - and solve the quadratic equation - // 0 = c + bv + av^2 - - // b = 2 * - double b = 2.0 * init1->minus(init2)->dot(vec1->minus(vec2)); - - // c = -r^2 + (I2 - I1)^T * (I2 - I1) - double c = -radius * radius + init2->minus(init1)->squaredMagnitude(); - - double discr = b * b - 4.0 * a * c; - if (discr < 0.0) { - return nullptr; - } - - double v1 = (-b - sqrt(discr)) / (2.0 * a); - double v2 = (-b + sqrt(discr)) / (2.0 * a); - - if (v1 <= v2 && ((v1 <= 1.0 && 1.0 <= v2) || (v1 <= 0.0 && 0.0 <= v2) || - (0.0 <= v1 && v2 <= 1.0))) { - // Pick a good "time" at which to report the collision. - double v; - if (v1 <= 0.0) { - // The collision started before this frame. Report it at the start of - // the frame. - v = 0.0; - } else { - // The collision started during this frame. Report it at that moment. - v = v1; - } - - shared_ptr result1 = init1->plus(vec1->times(v)); - shared_ptr result2 = init2->plus(vec2->times(v)); - - shared_ptr result = result1->plus(result2)->times(0.5); - if (result->_x >= Constants::MIN_X && result->_x <= Constants::MAX_X && - result->_y >= Constants::MIN_Y && result->_y <= Constants::MAX_Y && - result->_z >= Constants::MIN_Z && result->_z <= Constants::MAX_Z) { - return result; - } - } - - return nullptr; - } - // the planes have the same speeds and are moving in parallel (or they are not - // moving at all) they thus have the same distance all the time ; we - // calculate it from the initial point - - // dist = || i2 - i1 || = sqrt( ( i2 - i1 )^T * ( i2 - i1 ) ) - double dist = init2->minus(init1)->magnitude(); - if (dist <= radius) { - return init1->plus(init2)->times(0.5); - } - - return nullptr; -} -} // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Motion.h b/benchmarks/C++/src/CD/Motion.h deleted file mode 100644 index 86d50dd4..00000000 --- a/benchmarks/C++/src/CD/Motion.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef MOTION -#define MOTION - -#include -#include "CallSign.h" -#include "Constants.h" -#include "Vector3D.h" - -using namespace std; - -namespace CD { -class Motion { - private: - shared_ptr delta() const; - - public: - shared_ptr _callsign; - shared_ptr _posOne; - shared_ptr _posTwo; - - Motion(shared_ptr callsign, - shared_ptr posOne, - shared_ptr posTwo); - - shared_ptr findIntersection(shared_ptr other); -}; -} // namespace CD - -#endif // MOTION \ No newline at end of file diff --git a/benchmarks/C++/src/CD/RedBlackTree.cpp b/benchmarks/C++/src/CD/RedBlackTree.cpp deleted file mode 100644 index 07834a5a..00000000 --- a/benchmarks/C++/src/CD/RedBlackTree.cpp +++ /dev/null @@ -1,511 +0,0 @@ -#include -#include -#include - -using namespace std; - -namespace CD { - -template -class RedBlackTree { - private: - enum Color { RED = 0, BLACK = 1 }; - - class Node : public enable_shared_from_this { - public: - // Moved to public - K _key; - V _value; - shared_ptr _left; - shared_ptr _right; - shared_ptr _parent; - Color _color; - - shared_ptr successor(void) { - shared_ptr x = this->shared_from_this(); - if (x->_right != nullptr) { - return treeMinimum(x->_right); - } - shared_ptr y = x->_parent; - while (y != nullptr && x == y->_right) { - x = y; - y = y->_parent; - } - return y; - } - - // Moved to public - - Node(K key, V value) { - _key = key; - _value = value; - _left = nullptr; - _right = nullptr; - _left = nullptr; - _parent = nullptr; - _color = RED; - } - }; - - class InsertResult { - public: - bool _isNewEntry; - shared_ptr _newNode; - V _oldValue; - - InsertResult(bool isNewEntry, shared_ptr newNode, V oldValue) { - _isNewEntry = isNewEntry; - _newNode = newNode; - _oldValue = oldValue; - } - }; - - shared_ptr _root; - - static shared_ptr treeMinimum(shared_ptr x) { - shared_ptr current = x; - while (current->_left != nullptr) { - current = current->_left; - } - return current; - } - - shared_ptr treeInsertPtr(K key, V value) { - shared_ptr y = nullptr; - shared_ptr x = _root; - - while (x != nullptr) { - y = x; - - int comparisonResult = key->compareTo(x->_key); - if (comparisonResult < 0) { - x = x->_left; - } else if (comparisonResult > 0) { - x = x->_right; - } else { - V oldValue = x->_value; - x->_value = value; - return make_shared(false, nullptr, oldValue); - } - } - - shared_ptr z = make_shared(key, value); - z->_parent = y; - if (y == nullptr) { - _root = z; - } else { - if (key->compareTo(y->_key) < 0) { - y->_left = z; - } else { - y->_right = z; - } - } - return make_shared(true, z, nullptr); - } - - shared_ptr treeInsert(K key, V value) { - shared_ptr y = nullptr; - shared_ptr x = _root; - - while (x != nullptr) { - y = x; - int comparisonResult = key->compareTo(x->_key); - if (comparisonResult < 0) { - x = x->_left; - } else if (comparisonResult > 0) { - x = x->_right; - } else { - V oldValue = x->_value; - x->_value = value; - return make_shared(false, nullptr, oldValue); - } - } - - shared_ptr z = make_shared(key, value); - z->_parent = y; - if (y == nullptr) { - _root = z; - } else { - if (key->compareTo(y->_key) < 0) { - y->_left = z; - } else { - y->_right = z; - } - } - return make_shared(true, z, V()); - } - - shared_ptr leftRotate(shared_ptr x) { - shared_ptr y = x->_right; - - // Turn y's left subtree into x's right subtree. - x->_right = y->_left; - if (y->_left != nullptr) { - y->_left->_parent = x; - } - - // Link x's parent to y - y->_parent = x->_parent; - if (x->_parent == nullptr) { - _root = y; - } else { - if (x == x->_parent->_left) { - x->_parent->_left = y; - } else { - x->_parent->_right = y; - } - } - - // Put x on y's left. - y->_left = x; - x->_parent = y; - - return y; - } - - shared_ptr rightRotate(shared_ptr y) { - shared_ptr x = y->_left; - - // Turn x's right subtree into y's left subtree. - y->_left = x->_right; - if (x->_right != nullptr) { - x->_right->_parent = y; - } - - // Link y's parent to x; - x->_parent = y->_parent; - if (y->_parent == nullptr) { - _root = x; - } else { - if (y == y->_parent->_left) { - y->_parent->_left = x; - } else { - y->_parent->_right = x; - } - } - - x->_right = y; - y->_parent = x; - - return x; - } - - void removeFixup(shared_ptr x, shared_ptr xParent) { - while (x != _root && (x == nullptr || x->_color == BLACK)) { - if (x == xParent->_left) { - // Note: the text points out that w cannot be null-> The reason is not - // obvious from simply looking at the code; it comes about from the - // properties of the red-black tree. - shared_ptr w = xParent->_right; - if (w->_color == RED) { - // Case 1 - w->_color = BLACK; - xParent->_color = RED; - leftRotate(xParent); - w = xParent->_right; - } - if ((w->_left == nullptr || w->_left->_color == BLACK) && - (w->_right == nullptr || w->_right->_color == BLACK)) { - // Case 2 - w->_color = RED; - x = xParent; - xParent = x->_parent; - } else { - if (w->_right == nullptr || w->_right->_color == BLACK) { - // Case 3 - w->_left->_color = BLACK; - w->_color = RED; - rightRotate(w); - w = xParent->_right; - } - // Case 4 - w->_color = xParent->_color; - xParent->_color = BLACK; - if (w->_right != nullptr) { - w->_right->_color = BLACK; - } - leftRotate(xParent); - x = _root; - xParent = x->_parent; - } - } else { - // Same as "then" clause with "right" and "left" exchanged. - shared_ptr w = xParent->_left; - if (w->_color == RED) { - // Case 1 - w->_color = BLACK; - xParent->_color = RED; - rightRotate(xParent); - w = xParent->_left; - } - if ((w->_right == nullptr || w->_right->_color == BLACK) && - (w->_left == nullptr || w->_left->_color == BLACK)) { - // Case 2 - w->_color = RED; - x = xParent; - xParent = x->_parent; - } else { - if (w->_left == nullptr || w->_left->_color == BLACK) { - // Case 3 - w->_right->_color = BLACK; - w->_color = RED; - leftRotate(w); - w = xParent->_left; - } - // Case 4 - w->_color = xParent->_color; - xParent->_color = BLACK; - if (w->_left != nullptr) { - w->_left->_color = BLACK; - } - rightRotate(xParent); - x = _root; - xParent = x->_parent; - } - } - } - if (x != nullptr) { - x->_color = BLACK; - } - } - - public: - // moved public - class Entry { - public: - K _key; - V _value; - - Entry(K key, V value) { - _key = key; - _value = value; - } - }; - // moved public - - RedBlackTree() { _root = nullptr; }; - - V putPtr(K key, V value) { - shared_ptr insertionResult = treeInsertPtr(key, value); - - if (!insertionResult->_isNewEntry) { - return insertionResult->_oldValue; - } - shared_ptr x = insertionResult->_newNode; - - while (x != _root && x->_parent->_color == RED) { - if (x->_parent == x->_parent->_parent->_left) { - shared_ptr y = x->_parent->_parent->_right; - if (y != nullptr && y->_color == RED) { - // Case 1 - x->_parent->_color = BLACK; - y->_color = BLACK; - x->_parent->_parent->_color = RED; - x = x->_parent->_parent; - } else { - if (x == x->_parent->_right) { - // Case 2 - x = x->_parent; - leftRotate(x); - } - // Case 3 - x->_parent->_color = BLACK; - x->_parent->_parent->_color = RED; - rightRotate(x->_parent->_parent); - } - } else { - // Same as "then" clause with "right" and "left" exchanged. - shared_ptr y = x->_parent->_parent->_left; - if (y != nullptr && y->_color == RED) { - // Case 1 - x->_parent->_color = BLACK; - y->_color = BLACK; - x->_parent->_parent->_color = RED; - x = x->_parent->_parent; - } else { - if (x == x->_parent->_left) { - // Case 2 - x = x->_parent; - rightRotate(x); - } - // Case 3 - x->_parent->_color = BLACK; - x->_parent->_parent->_color = RED; - leftRotate(x->_parent->_parent); - } - } - } - _root->_color = BLACK; - return nullptr; - } - - V put(K key, V value) { - shared_ptr insertionResult = treeInsert(key, value); - - if (!insertionResult->_isNewEntry) { - return insertionResult->_oldValue; - } - shared_ptr x = insertionResult->_newNode; - - while (x != _root && x->_parent->_color == RED) { - if (x->_parent == x->_parent->_parent->_left) { - shared_ptr y = x->_parent->_parent->_right; - if (y != nullptr && y->_color == RED) { - // Case 1 - x->_parent->_color = BLACK; - y->_color = BLACK; - x->_parent->_parent->_color = RED; - x = x->_parent->_parent; - } else { - if (x == x->_parent->_right) { - // Case 2 - x = x->_parent; - leftRotate(x); - } - // Case 3 - x->_parent->_color = BLACK; - x->_parent->_parent->_color = RED; - rightRotate(x->_parent->_parent); - } - } else { - // Same as "then" clause with "right" and "left" exchanged. - shared_ptr y = x->_parent->_parent->_left; - if (y != nullptr && y->_color == RED) { - // Case 1 - x->_parent->_color = BLACK; - y->_color = BLACK; - x->_parent->_parent->_color = RED; - x = x->_parent->_parent; - } else { - if (x == x->_parent->_left) { - // Case 2 - x = x->_parent; - rightRotate(x); - } - // Case 3 - x->_parent->_color = BLACK; - x->_parent->_parent->_color = RED; - leftRotate(x->_parent->_parent); - } - } - } - _root->_color = BLACK; - return V(); - } - - V remove(K key) { - shared_ptr z = findNode(key); - if (z == nullptr) { - return nullptr; - } - - // Y is the node to be unlinked from the tree. - shared_ptr y; - if (z->_left == nullptr || z->_right == nullptr) { - y = z; - } else { - y = z->successor(); - } - - // Y is guaranteed to be non-null at this point. - shared_ptr x; - if (y->_left != nullptr) { - x = y->_left; - } else { - x = y->_right; - } - // X is the child of y which might potentially replace y in the tree. X - // might be null at this point. - shared_ptr xParent; - if (x != nullptr) { - x->_parent = y->_parent; - xParent = x->_parent; - } else { - xParent = y->_parent; - } - if (y->_parent == nullptr) { - _root = x; - } else { - if (y == y->_parent->_left) { - y->_parent->_left = x; - } else { - y->_parent->_right = x; - } - } - - if (y != z) { - if (y->_color == BLACK) { - removeFixup(x, xParent); - } - - y->_parent = z->_parent; - y->_color = z->_color; - y->_left = z->_left; - y->_right = z->_right; - - if (z->_left != nullptr) { - z->_left->_parent = y; - } - if (z->_right != nullptr) { - z->_right->_parent = y; - } - if (z->_parent != nullptr) { - if (z->_parent->_left == z) { - z->_parent->_left = y; - } else { - z->_parent->_right = y; - } - } else { - _root = y; - } - } else if (y->_color == BLACK) { - removeFixup(x, xParent); - } - - return z->_value; - } - - V getPtr(K key) { - shared_ptr node = findNode(key); - if (node == nullptr) { - return nullptr; - } - return node->_value; - } - - V get(K key) { - shared_ptr node = findNode(key); - if (node == nullptr) { - return V(); - } - return node->_value; - } - - void forEach(function)> fn) { - if (_root == nullptr) { - return; - } - shared_ptr current = treeMinimum(_root); - while (current != nullptr) { - fn(make_shared(current->_key, current->_value)); - current = current->successor(); - } - } - - shared_ptr findNode(K key) { - shared_ptr current = _root; - while (current != nullptr) { - int comparisonResult = key->compareTo(current->_key); - if (comparisonResult == 0) { - return current; - } - if (comparisonResult < 0) { - current = current->_left; - } else { - current = current->_right; - } - } - return nullptr; - } -}; -}; // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Simulator.cpp b/benchmarks/C++/src/CD/Simulator.cpp deleted file mode 100644 index 4dd16309..00000000 --- a/benchmarks/C++/src/CD/Simulator.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "Simulator.h" - -using namespace std; - -namespace CD { - -Simulator::Simulator(int numAircraft) { - _aircraft = make_shared>>(); - - for (int i = 0; i < numAircraft; i++) { - _aircraft->append(make_shared(i)); - } -} - -shared_ptr>> Simulator::simulate(double time) { - shared_ptr>> frame = - make_shared>>(); - - for (unsigned long int i = 0; i < _aircraft->size(); i += 2) { - frame->append(make_shared( - _aircraft->atPtr(i), - make_shared(time, cos(time) * 2 + i * 3, 10))); - frame->append(make_shared( - _aircraft->atPtr(i + 1), - make_shared(time, sin(time) * 2 + i * 3, 10))); - } - return frame; -} -}; // namespace CD diff --git a/benchmarks/C++/src/CD/Simulator.h b/benchmarks/C++/src/CD/Simulator.h deleted file mode 100644 index 24a6eaef..00000000 --- a/benchmarks/C++/src/CD/Simulator.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef SIMULATOR -#define SIMULATOR - -#include -#include "../som/Vector.cpp" -#include "Aircraft.h" - -using namespace std; - -namespace CD { -class Simulator { - private: - shared_ptr>> _aircraft; - - public: - Simulator(int numAircraft); - - shared_ptr>> simulate(double time); -}; -}; // namespace CD - -#endif // SIMULATOR \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Vector2D.cpp b/benchmarks/C++/src/CD/Vector2D.cpp deleted file mode 100644 index d09a94f5..00000000 --- a/benchmarks/C++/src/CD/Vector2D.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "Vector2D.h" - -namespace CD { -int Vector2D::compareNumbers(double a, double b) { - if (a == b) { - return 0; - } - if (a < b) { - return -1; - } - if (a > b) { - return 1; - } - - // We say that NaN is smaller than non-NaN. - if (a == a) { - return 1; - } - return -1; -} - -Vector2D::Vector2D(double x, double y) { - _x = x; - _y = y; -} - -shared_ptr Vector2D::plus(shared_ptr other) const { - return make_shared(_x + other->_x, _y + other->_y); -} - -shared_ptr Vector2D::minus(shared_ptr other) const { - return make_shared(_x - other->_x, _y - other->_y); -} - -int Vector2D::compareTo(shared_ptr other) { - int result = compareNumbers(_x, other->_x); - - if (result != 0) { - return result; - } - - return compareNumbers(_y, other->_y); -} -} // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Vector2D.h b/benchmarks/C++/src/CD/Vector2D.h deleted file mode 100644 index 3bad720d..00000000 --- a/benchmarks/C++/src/CD/Vector2D.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef VECTOR2D -#define VECTOR2D - -#include -using namespace std; - -namespace CD { - -class Vector2D { - private: - static int compareNumbers(double a, double b); - - public: - double _x; - double _y; - - Vector2D(double x, double y); - shared_ptr plus(shared_ptr other) const; - shared_ptr minus(shared_ptr other) const; - int compareTo(shared_ptr other); -}; -} // namespace CD - -#endif // VECTOR2D \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Vector3D.cpp b/benchmarks/C++/src/CD/Vector3D.cpp deleted file mode 100644 index 81539ab9..00000000 --- a/benchmarks/C++/src/CD/Vector3D.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "Vector3D.h" -#include - -namespace CD { - -Vector3D::Vector3D(double x, double y, double z) { - _x = x; - _y = y; - _z = z; -} - -shared_ptr Vector3D::plus(shared_ptr other) const { - return make_shared(_x + other->_x, _y + other->_y, _z + other->_z); -} - -shared_ptr Vector3D::minus(shared_ptr other) const { - return make_shared(_x - other->_x, _y - other->_y, _z - other->_z); -} - -double Vector3D::dot(shared_ptr other) { - return _x * other->_x + _y * other->_y + _z * other->_z; -} - -double Vector3D::squaredMagnitude() { - return dot(shared_from_this()); -} - -double Vector3D::magnitude() { - return sqrt(squaredMagnitude()); -} - -shared_ptr Vector3D::times(double amount) const { - return make_shared(_x * amount, _y * amount, _z * amount); -} -}; // namespace CD \ No newline at end of file diff --git a/benchmarks/C++/src/CD/Vector3D.h b/benchmarks/C++/src/CD/Vector3D.h deleted file mode 100644 index 8db8ee3a..00000000 --- a/benchmarks/C++/src/CD/Vector3D.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef VECTOR3D -#define VECTOR3D - -#include -#include -using namespace std; - -namespace CD { - -class Vector3D : public enable_shared_from_this { - public: - double _x; - double _y; - double _z; - - Vector3D(double x, double y, double z); - - shared_ptr plus(shared_ptr other) const; - shared_ptr minus(shared_ptr other) const; - double dot(shared_ptr other); - double squaredMagnitude(); - double magnitude(); - shared_ptr times(double amount) const; -}; -} // namespace CD - -#endif // VECTOR3D \ No newline at end of file diff --git a/benchmarks/C++/src/cd.h b/benchmarks/C++/src/cd.h new file mode 100644 index 00000000..1fe3df67 --- /dev/null +++ b/benchmarks/C++/src/cd.h @@ -0,0 +1,947 @@ +#pragma once + +#include +#include "benchmark.h" +#include "som/error.h" +#include "som/vector.h" + +class Vector2D { + private: + static int32_t compareNumbers(double a, double b) { + if (a == b) { + return 0; + } + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + + // We say that NaN is smaller than non-NaN. + if (a == a) { + return 1; + } + return -1; + } + + public: + const double x; + const double y; + + constexpr Vector2D(double x, double y) : x(x), y(y) {} + + [[nodiscard]] Vector2D plus(const Vector2D& other) const { + return {x + other.x, y + other.y}; + } + + [[nodiscard]] Vector2D minus(const Vector2D& other) const { + return {x - other.x, y - other.y}; + } + + [[nodiscard]] int32_t compareTo(const Vector2D& other) const { + const int32_t result = compareNumbers(x, other.x); + + if (result != 0) { + return result; + } + + return compareNumbers(y, other.y); + } +}; + +class Vector3D { + public: + double x; + double y; + double z; + + constexpr Vector3D(double x, double y, double z) : x(x), y(y), z(z) {} + constexpr Vector3D(const Vector3D& other) = default; + + Vector3D() = default; + + Vector3D& operator=(const Vector3D& other) = default; + + [[nodiscard]] Vector3D plus(const Vector3D& other) const { + return {x + other.x, y + other.y, z + other.z}; + } + + [[nodiscard]] Vector3D minus(const Vector3D& other) const { + return {x - other.x, y - other.y, z - other.z}; + } + + [[nodiscard]] double dot(const Vector3D& other) const { + return x * other.x + y * other.y + z * other.z; + } + + [[nodiscard]] double squaredMagnitude() const { return dot(*this); } + [[nodiscard]] double magnitude() const { return sqrt(squaredMagnitude()); } + + [[nodiscard]] Vector3D times(double amount) const { + return {x * amount, y * amount, z * amount}; + } +}; + +template +class RedBlackTree { + private: + enum Color { RED = 0, BLACK = 1 }; + + class Node { + friend class RedBlackTree; + + private: + K _key; + V _value; + Node* _left{nullptr}; + Node* _right{nullptr}; + Node* _parent{nullptr}; + Color _color{RED}; + + Node* successor() { + Node* x = this; + if (x->_right != nullptr) { + return treeMinimum(x->_right); + } + Node* y = x->_parent; + while (y != nullptr && x == y->_right) { + x = y; + y = y->_parent; + } + return y; + } + + Node(K key, V value) : _key(key), _value(value) {} + ~Node() { + delete _left; + delete _right; + } + }; + + class InsertResult { + public: + const bool isNewEntry; + Node* const newNode; + V oldValue; + + InsertResult(bool isNewEntry, Node* newNode, V oldValue) + : isNewEntry(isNewEntry), newNode(newNode), oldValue(oldValue) {} + }; + + Node* _root{nullptr}; + + static Node* treeMinimum(Node* x) { + Node* current = x; + while (current->_left != nullptr) { + current = current->_left; + } + return current; + } + + InsertResult treeInsert(K key, V value) { + Node* y = nullptr; + Node* x = _root; + + while (x != nullptr) { + y = x; + const int32_t comparisonResult = key.compareTo(x->_key); + if (comparisonResult < 0) { + x = x->_left; + } else if (comparisonResult > 0) { + x = x->_right; + } else { + V oldValue = x->_value; + x->_value = value; + return InsertResult(false, nullptr, oldValue); + } + } + + Node* z = new Node(key, value); + z->_parent = y; + if (y == nullptr) { + _root = z; + } else { + if (key.compareTo(y->_key) < 0) { + y->_left = z; + } else { + y->_right = z; + } + } + return InsertResult(true, z, V()); + } + + Node* leftRotate(Node* x) { + Node* y = x->_right; + + // Turn y's left subtree into x's right subtree. + x->_right = y->_left; + if (y->_left != nullptr) { + y->_left->_parent = x; + } + + // Link x's parent to y + y->_parent = x->_parent; + if (x->_parent == nullptr) { + _root = y; + } else { + if (x == x->_parent->_left) { + x->_parent->_left = y; + } else { + x->_parent->_right = y; + } + } + + // Put x on y's left. + y->_left = x; + x->_parent = y; + + return y; + } + + Node* rightRotate(Node* y) { + Node* x = y->_left; + + // Turn x's right subtree into y's left subtree. + y->_left = x->_right; + if (x->_right != nullptr) { + x->_right->_parent = y; + } + + // Link y's parent to x; + x->_parent = y->_parent; + if (y->_parent == nullptr) { + _root = x; + } else { + if (y == y->_parent->_left) { + y->_parent->_left = x; + } else { + y->_parent->_right = x; + } + } + + x->_right = y; + y->_parent = x; + + return x; + } + + void removeFixup(Node* x, Node* xParent) { + while (x != _root && (x == nullptr || x->_color == BLACK)) { + if (x == xParent->_left) { + // Note: the text points out that w cannot be null-> The reason is not + // obvious from simply looking at the code; it comes about from the + // properties of the red-black tree. + Node* w = xParent->_right; + if (w->_color == RED) { + // Case 1 + w->_color = BLACK; + xParent->_color = RED; + leftRotate(xParent); + w = xParent->_right; + } + if ((w->_left == nullptr || w->_left->_color == BLACK) && + (w->_right == nullptr || w->_right->_color == BLACK)) { + // Case 2 + w->_color = RED; + x = xParent; + xParent = x->_parent; + } else { + if (w->_right == nullptr || w->_right->_color == BLACK) { + // Case 3 + w->_left->_color = BLACK; + w->_color = RED; + rightRotate(w); + w = xParent->_right; + } + // Case 4 + w->_color = xParent->_color; + xParent->_color = BLACK; + if (w->_right != nullptr) { + w->_right->_color = BLACK; + } + leftRotate(xParent); + x = _root; + xParent = x->_parent; + } + } else { + // Same as "then" clause with "right" and "left" exchanged. + Node* w = xParent->_left; + if (w->_color == RED) { + // Case 1 + w->_color = BLACK; + xParent->_color = RED; + rightRotate(xParent); + w = xParent->_left; + } + if ((w->_right == nullptr || w->_right->_color == BLACK) && + (w->_left == nullptr || w->_left->_color == BLACK)) { + // Case 2 + w->_color = RED; + x = xParent; + xParent = x->_parent; + } else { + if (w->_left == nullptr || w->_left->_color == BLACK) { + // Case 3 + w->_right->_color = BLACK; + w->_color = RED; + leftRotate(w); + w = xParent->_left; + } + // Case 4 + w->_color = xParent->_color; + xParent->_color = BLACK; + if (w->_left != nullptr) { + w->_left->_color = BLACK; + } + rightRotate(xParent); + x = _root; + xParent = x->_parent; + } + } + } + if (x != nullptr) { + x->_color = BLACK; + } + } + + public: + class Entry { + public: + K const key; + V const value; + + Entry(K key, V value) : key(key), value(value) {} + }; + + RedBlackTree() = default; + ~RedBlackTree() { delete _root; } + + std::optional put(K key, V value) { + InsertResult insertionResult = treeInsert(key, value); + + if (!insertionResult.isNewEntry) { + return insertionResult.oldValue; + } + Node* x = insertionResult.newNode; + + while (x != _root && x->_parent->_color == RED) { + if (x->_parent == x->_parent->_parent->_left) { + Node* y = x->_parent->_parent->_right; + if (y != nullptr && y->_color == RED) { + // Case 1 + x->_parent->_color = BLACK; + y->_color = BLACK; + x->_parent->_parent->_color = RED; + x = x->_parent->_parent; + } else { + if (x == x->_parent->_right) { + // Case 2 + x = x->_parent; + leftRotate(x); + } + // Case 3 + x->_parent->_color = BLACK; + x->_parent->_parent->_color = RED; + rightRotate(x->_parent->_parent); + } + } else { + // Same as "then" clause with "right" and "left" exchanged. + Node* y = x->_parent->_parent->_left; + if (y != nullptr && y->_color == RED) { + // Case 1 + x->_parent->_color = BLACK; + y->_color = BLACK; + x->_parent->_parent->_color = RED; + x = x->_parent->_parent; + } else { + if (x == x->_parent->_left) { + // Case 2 + x = x->_parent; + rightRotate(x); + } + // Case 3 + x->_parent->_color = BLACK; + x->_parent->_parent->_color = RED; + leftRotate(x->_parent->_parent); + } + } + } + _root->_color = BLACK; + return {}; + } + + std::optional remove(K key) { + Node* z = findNode(key); + if (z == nullptr) { + return {}; + } + + // Y is the node to be unlinked from the tree. + Node* y = nullptr; + if (z->_left == nullptr || z->_right == nullptr) { + y = z; + } else { + y = z->successor(); + } + + // Y is guaranteed to be non-null at this point. + Node* x = nullptr; + if (y->_left != nullptr) { + x = y->_left; + } else { + x = y->_right; + } + // X is the child of y which might potentially replace y in the tree. X + // might be null at this point. + Node* xParent = nullptr; + if (x != nullptr) { + x->_parent = y->_parent; + xParent = x->_parent; + } else { + xParent = y->_parent; + } + if (y->_parent == nullptr) { + _root = x; + } else { + if (y == y->_parent->_left) { + y->_parent->_left = x; + } else { + y->_parent->_right = x; + } + } + + if (y != z) { + if (y->_color == BLACK) { + removeFixup(x, xParent); + } + + y->_parent = z->_parent; + y->_color = z->_color; + y->_left = z->_left; + y->_right = z->_right; + + if (z->_left != nullptr) { + z->_left->_parent = y; + } + if (z->_right != nullptr) { + z->_right->_parent = y; + } + if (z->_parent != nullptr) { + if (z->_parent->_left == z) { + z->_parent->_left = y; + } else { + z->_parent->_right = y; + } + } else { + _root = y; + } + } else if (y->_color == BLACK) { + removeFixup(x, xParent); + } + + return z->_value; + } + + V* get(K key) { + Node* node = findNode(key); + if (node == nullptr) { + return nullptr; + } + return &node->_value; + } + + void forEach(std::function fn) { + if (_root == nullptr) { + return; + } + Node* current = treeMinimum(_root); + while (current != nullptr) { + Entry entry{current->_key, current->_value}; + fn(entry); + current = current->successor(); + } + } + + void destroyValues() { + if (_root == nullptr) { + return; + } + Node* current = treeMinimum(_root); + while (current != nullptr) { + Entry entry{current->_key, current->_value}; + delete entry.value; + current = current->successor(); + } + } + + Node* findNode(K key) { + Node* current = _root; + while (current != nullptr) { + const int32_t comparisonResult = key.compareTo(current->_key); + if (comparisonResult == 0) { + return current; + } + if (comparisonResult < 0) { + current = current->_left; + } else { + current = current->_right; + } + } + return nullptr; + } +}; + +class CallSign { + private: + int32_t _value; + + public: + explicit CallSign(int32_t value) : _value(value) {} + CallSign(const CallSign& other) = default; + + CallSign() = default; + + CallSign& operator=(const CallSign& other) = default; + + [[nodiscard]] int32_t compareTo(const CallSign& other) const { + return (_value == other._value) ? 0 : ((_value < other._value) ? -1 : 1); + } +}; + +class Collision { + public: + CallSign aircraftA; + CallSign aircraftB; + Vector3D position; + + Collision(const CallSign& aircraftA, + const CallSign& aircraftB, + const Vector3D& position) + : aircraftA(aircraftA), aircraftB(aircraftB), position(position) {} + + explicit Collision() = default; +}; + +class Constants { + public: + constexpr static const double MIN_X = 0.0; + constexpr static const double MIN_Y = 0.0; + constexpr static const double MAX_X = 1000.0; + constexpr static const double MAX_Y = 1000.0; + constexpr static const double MIN_Z = 0.0; + constexpr static const double MAX_Z = 10.0; + constexpr static const double PROXIMITY_RADIUS = 1.0; + constexpr static const double GOOD_VOXEL_SIZE = PROXIMITY_RADIUS * 2.0; +}; + +class Motion { + private: + [[nodiscard]] Vector3D delta() const { return posTwo.minus(posOne); } + + public: + CallSign callsign; + Vector3D posOne; + Vector3D posTwo; + + Motion(const CallSign& callsign, + const Vector3D& posOne, + const Vector3D& posTwo) + : callsign(callsign), posOne(posOne), posTwo(posTwo) {} + + explicit Motion() = default; + Motion(const Motion& other) = default; + Motion& operator=(const Motion& other) = default; + + [[nodiscard]] std::optional findIntersection( + const Motion& other) const { + const Vector3D& init1 = posOne; + const Vector3D& init2 = other.posOne; + const Vector3D vec1 = delta(); + const Vector3D vec2 = other.delta(); + const double radius = Constants::PROXIMITY_RADIUS; + + // this test is not geometrical 3-d intersection test, it takes the fact + // that the aircraft move into account ; so it is more like a 4d test (it + // assumes that both of the aircraft have a constant speed over the tested + // interval) + + // we thus have two points, each of them moving on its line segment at + // constant speed ; we are looking for times when the distance between these + // two points is smaller than r + + // vec1 is vector of aircraft 1 + // vec2 is vector of aircraft 2 + + // a = (V2 - V1)^T * (V2 - V1) + const double a = vec2.minus(vec1).squaredMagnitude(); + + if (a != 0.0) { + // we are first looking for instances of time when the planes are exactly + // r from each other at least one plane is moving ; if the planes are + // moving in parallel, they do not have constant speed + + // if the planes are moving in parallel, then + // if the faster starts behind the slower, we can have 2, 1, or 0 + // solutions if the faster plane starts in front of the slower, we can + // have 0 or 1 solutions + + // if the planes are not moving in parallel, then + + // point P1 = I1 + vV1 + // point P2 = I2 + vV2 + // - looking for v, such that dist(P1,P2) = || P1 - P2 || = r + + // it follows that || P1 - P2 || = sqrt( < P1-P2, P1-P2 > ) + // 0 = -r^2 + < P1 - P2, P1 - P2 > + // from properties of dot product + // 0 = -r^2 + + v * 2 + v^2 * + // so we calculate a, b, c - and solve the quadratic equation + // 0 = c + bv + av^2 + + // b = 2 * + const double b = 2.0 * init1.minus(init2).dot(vec1.minus(vec2)); + + // c = -r^2 + (I2 - I1)^T * (I2 - I1) + const double c = -radius * radius + init2.minus(init1).squaredMagnitude(); + + const double discr = b * b - 4.0 * a * c; + if (discr < 0.0) { + return {}; + } + + const double v1 = (-b - sqrt(discr)) / (2.0 * a); + const double v2 = (-b + sqrt(discr)) / (2.0 * a); + + if (v1 <= v2 && ((v1 <= 1.0 && 1.0 <= v2) || (v1 <= 0.0 && 0.0 <= v2) || + (0.0 <= v1 && v2 <= 1.0))) { + // Pick a good "time" at which to report the collision. + double v = 0.0; + if (v1 <= 0.0) { + // The collision started before this frame. Report it at the start of + // the frame. + v = 0.0; + } else { + // The collision started during this frame. Report it at that moment. + v = v1; + } + + const Vector3D result1 = init1.plus(vec1.times(v)); + const Vector3D result2 = init2.plus(vec2.times(v)); + + const Vector3D result = result1.plus(result2).times(0.5); + if (result.x >= Constants::MIN_X && result.x <= Constants::MAX_X && + result.y >= Constants::MIN_Y && result.y <= Constants::MAX_Y && + result.z >= Constants::MIN_Z && result.z <= Constants::MAX_Z) { + return result; + } + } + + return {}; + } + // the planes have the same speeds and are moving in parallel (or they are + // not moving at all) they thus have the same distance all the time ; we + // calculate it from the initial point + + // dist = || i2 - i1 || = sqrt( ( i2 - i1 )^T * ( i2 - i1 ) ) + const double dist = init2.minus(init1).magnitude(); + if (dist <= radius) { + return init1.plus(init2).times(0.5); + } + + return {}; + } +}; + +class Aircraft { + public: + CallSign callsign; + Vector3D position; + + Aircraft(const CallSign& callsign, const Vector3D& position) + : callsign(callsign), position(position) {} + + explicit Aircraft() = default; +}; + +class CollisionDetector { + private: + RedBlackTree _state{}; + constexpr static const Vector2D _horizontal{Constants::GOOD_VOXEL_SIZE, 0.0}; + constexpr static const Vector2D _vertical{0.0, Constants::GOOD_VOXEL_SIZE}; + + static bool isInVoxel(const Vector2D& voxel, const Motion& motion) { + if (voxel.x > Constants::MAX_X || voxel.x < Constants::MIN_X || + voxel.y > Constants::MAX_Y || voxel.y < Constants::MIN_Y) { + return false; + } + + const Vector3D& init = motion.posOne; + const Vector3D& fin = motion.posTwo; + + const double v_s = Constants::GOOD_VOXEL_SIZE; + const double r = Constants::PROXIMITY_RADIUS / 2.0; + + const double v_x = voxel.x; + const double x0 = init.x; + const double xv = fin.x - init.x; + + const double v_y = voxel.y; + const double y0 = init.y; + const double yv = fin.y - init.y; + + double low_x = (v_x - r - x0) / xv; + double high_x = (v_x + v_s + r - x0) / xv; + + if (xv < 0.0) { + const double tmp = low_x; + low_x = high_x; + high_x = tmp; + } + + double low_y = (v_y - r - y0) / yv; + double high_y = (v_y + v_s + r - y0) / yv; + + if (yv < 0.0) { + const double tmp = low_y; + low_y = high_y; + high_y = tmp; + } + + return ( + ((xv == 0.0 && v_x <= x0 + r && + x0 - r <= v_x + v_s) /* no motion in x */ + || (low_x <= 1.0 && 1.0 <= high_x) || + (low_x <= 0.0 && 0.0 <= high_x) || (0.0 <= low_x && high_x <= 1.0)) && + ((yv == 0.0 && v_y <= y0 + r && + y0 - r <= v_y + v_s) /* no motion in y */ + || + ((low_y <= 1.0 && 1.0 <= high_y) || (low_y <= 0.0 && 0.0 <= high_y) || + (0.0 <= low_y && high_y <= 1.0))) && + (xv == 0.0 || yv == 0.0 || /* no motion in x or y or both */ + (low_y <= high_x && high_x <= high_y) || + (low_y <= low_x && low_x <= high_y) || + (low_x <= low_y && high_y <= high_x))); + } + + static void putIntoMap(RedBlackTree*>& voxelMap, + const Vector2D& voxel, + const Motion& motion) { + Vector** array = voxelMap.get(voxel); + if (array == nullptr) { + auto* arr = new Vector(); + arr->append(motion); + voxelMap.put(voxel, arr); + } else { + (*array)->append(motion); + } + } + + void recurse(RedBlackTree*>& voxelMap, + RedBlackTree& seen, + const Vector2D& nextVoxel, + const Motion& motion) { + if (!isInVoxel(nextVoxel, motion)) { + return; + } + if (seen.put(nextVoxel, true) == true) { + return; + } + putIntoMap(voxelMap, nextVoxel, motion); + + recurse(voxelMap, seen, nextVoxel.minus(_horizontal), motion); + recurse(voxelMap, seen, nextVoxel.plus(_horizontal), motion); + recurse(voxelMap, seen, nextVoxel.minus(_vertical), motion); + recurse(voxelMap, seen, nextVoxel.plus(_vertical), motion); + recurse(voxelMap, seen, nextVoxel.minus(_horizontal).minus(_vertical), + motion); + recurse(voxelMap, seen, nextVoxel.minus(_horizontal).plus(_vertical), + motion); + recurse(voxelMap, seen, nextVoxel.plus(_horizontal).minus(_vertical), + motion); + recurse(voxelMap, seen, nextVoxel.plus(_horizontal).plus(_vertical), + motion); + } + + Vector*>* reduceCollisionSet(Vector& motions) { + RedBlackTree*> voxelMap{}; + motions.forEach([this, &voxelMap](const Motion& motion) -> void { + drawMotionOnVoxelMap(voxelMap, motion); + }); + + auto* result = new Vector*>(); + + voxelMap.forEach( + [result](RedBlackTree*>::Entry& e) -> void { + if (e.value->size() > 1) { + result->append(e.value); + } else { + delete e.value; + } + }); + return result; + } + + Vector2D voxelHash(Vector3D position) { + const auto xDiv = + static_cast(position.x / Constants::GOOD_VOXEL_SIZE); + const auto yDiv = + static_cast(position.y / Constants::GOOD_VOXEL_SIZE); + + double x = Constants::GOOD_VOXEL_SIZE * xDiv; + double y = Constants::GOOD_VOXEL_SIZE * yDiv; + + if (position.x < 0) { + x -= Constants::GOOD_VOXEL_SIZE; + } + if (position.y < 0) { + y -= Constants::GOOD_VOXEL_SIZE; + } + + return {x, y}; + } + + void drawMotionOnVoxelMap(RedBlackTree*>& voxelMap, + const Motion motion) { + RedBlackTree seen{}; + recurse(voxelMap, seen, voxelHash(motion.posOne), motion); + } + + public: + CollisionDetector() = default; + + Vector* handleNewFrame(Vector& frame) { + Vector motions{}; + RedBlackTree seen{}; + + frame.forEach([this, &seen, &motions](const Aircraft& aircraft) -> void { + std::optional oldPosition = + _state.put(aircraft.callsign, aircraft.position); + const Vector3D newPosition = aircraft.position; + seen.put(aircraft.callsign, true); + if (!oldPosition.has_value()) { + // Treat newly introduced aircraft as if they were stationary. + oldPosition = newPosition; + } + motions.append(Motion(aircraft.callsign, *oldPosition, newPosition)); + }); + + Vector toRemove{}; + _state.forEach( + [&seen, + &toRemove](const RedBlackTree::Entry& e) -> void { + bool* const wasSeen = seen.get(e.key); + if (wasSeen == nullptr || !*wasSeen) { + toRemove.append(e.key); + } + }); + + toRemove.forEach([this](const CallSign& e) -> void { _state.remove(e); }); + + Vector*>* allReduced = reduceCollisionSet(motions); + auto* collisions = new Vector(); + + allReduced->forEach( + [collisions](const Vector* const& reduced) -> void { + for (size_t i = 0; i < reduced->size(); ++i) { + const Motion* motion1 = reduced->at(i); + for (size_t j = i + 1; j < reduced->size(); ++j) { + const Motion* motion2 = reduced->at(j); + std::optional collision = + motion1->findIntersection(*motion2); + if (collision.has_value()) { + collisions->append(Collision(motion1->callsign, + motion2->callsign, *collision)); + } + } + } + }); + allReduced->destroyValues(); + delete allReduced; + return collisions; + } +}; + +class Simulator { + private: + Vector _aircraft{}; + + public: + explicit Simulator(int32_t numAircraft) { + for (int32_t i = 0; i < numAircraft; i += 1) { + _aircraft.append(CallSign(i)); + } + } + + Vector simulate(double time) { + Vector frame{}; + + for (size_t i = 0; i < _aircraft.size(); i += 2) { + frame.append(Aircraft( + *_aircraft.at(i), + Vector3D(time, cos(time) * 2 + static_cast(i) * 3, 10))); + frame.append(Aircraft( + *_aircraft.at(i + 1), + Vector3D(time, sin(time) * 2 + static_cast(i) * 3, 10))); + } + return frame; + } +}; + +class CD : public Benchmark { + private: + static size_t benchmark(int32_t numAircrafts) { + const int32_t numFrames = 200; + + Simulator simulator{numAircrafts}; + CollisionDetector detector{}; + size_t actualCollisions = 0; + + for (int32_t i = 0; i < numFrames; i++) { + const double time = i / 10.0; + Vector frame = simulator.simulate(time); + Vector* collisions = detector.handleNewFrame(frame); + actualCollisions += collisions->size(); + delete collisions; + } + + return actualCollisions; + } + + public: + bool inner_benchmark_loop(int32_t innerIterations) override { + return verify_result(benchmark(innerIterations), innerIterations); + } + + static bool verify_result(size_t actualCollisions, int32_t numAircrafts) { + if (numAircrafts == 1000) { + return actualCollisions == 14484; + } + if (numAircrafts == 500) { + return actualCollisions == 14484; + } + if (numAircrafts == 250) { + return actualCollisions == 10830; + } + if (numAircrafts == 200) { + return actualCollisions == 8655; + } + if (numAircrafts == 100) { + return actualCollisions == 4305; + } + if (numAircrafts == 10) { + return actualCollisions == 390; + } + if (numAircrafts == 2) { + return actualCollisions == 42; + } + + std::cout << "No verification result for " << numAircrafts << " found" + << std::endl; + std::cout << "Result is: " << actualCollisions << std::endl; + return false; + } + + void* benchmark() override { throw Error("Should never be reached"); } + bool verify_result(void*) override { throw Error("Should never be reached"); } +}; diff --git a/benchmarks/C++/src/json.h b/benchmarks/C++/src/json.h index f05d5658..a81b2c51 100644 --- a/benchmarks/C++/src/json.h +++ b/benchmarks/C++/src/json.h @@ -527,7 +527,7 @@ class JsonArray : public JsonValue { [[nodiscard]] size_t size() const { return _values.size(); } [[nodiscard]] const JsonValue* get(int index) const { - return _values.at(index); + return *_values.at(index); } [[nodiscard]] bool isArray() const override { return true; } @@ -595,7 +595,7 @@ class JsonObject : public JsonValue { int32_t indexOf(string name) const { int32_t index = _table.get(name); - if (index != -1 && name == _names.at(index)) { + if (index != -1 && name == *_names.at(index)) { return index; } throw Error("not yet implemented, not relevant for the benchmark"); @@ -622,7 +622,7 @@ class JsonObject : public JsonValue { throw Error("name is null"); } int32_t index = indexOf(name); - return index == -1 ? nullptr : _values.at(index); + return index == -1 ? nullptr : *_values.at(index); } [[nodiscard]] size_t size() const { return _names.size(); } diff --git a/benchmarks/C++/src/run.h b/benchmarks/C++/src/run.h index eafeda5c..968da0fe 100644 --- a/benchmarks/C++/src/run.h +++ b/benchmarks/C++/src/run.h @@ -4,6 +4,7 @@ #include #include "bounce.h" +#include "cd.h" #include "deltablue.h" #include "json.h" #include "list.h" @@ -56,6 +57,9 @@ class Run { if (name == "Bounce") { return []() -> Benchmark* { return new Bounce(); }; } + if (name == "CD") { + return []() -> Benchmark* { return new CD(); }; + } if (name == "Json") { return []() -> Benchmark* { return new Json(); }; } From 29c7db79d4f805b1f94b47816966cf8066d0547e Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 9 Jan 2024 16:15:34 +0000 Subject: [PATCH 16/40] [C++] Fix lint issues in Json Signed-off-by: Stefan Marr --- benchmarks/C++/src/json.h | 126 +++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 56 deletions(-) diff --git a/benchmarks/C++/src/json.h b/benchmarks/C++/src/json.h index a81b2c51..0c4d7d95 100644 --- a/benchmarks/C++/src/json.h +++ b/benchmarks/C++/src/json.h @@ -8,7 +8,7 @@ using std::string; -const string rapBenchmarkMinified = +const string rapBenchmarkMinified = // NOLINT "{\"head\":{\"requestCounter\":4},\"operations\":[[\"destroy\",\"w54\"],[" "\"set\",\"w2\",{\"activeControl\":\"w99\"}],[\"set\",\"w21\",{" "\"customVariant\":\"variant_navigation\"}],[\"set\",\"w28\",{" @@ -454,7 +454,7 @@ class HashIndexTable { public: void add(const std::string& name, int32_t index) { - int32_t slot = hashSlotFor(name); + const int32_t slot = hashSlotFor(name); if (index < 0xff) { // increment by 1, 0 stands for empty _hashTable[slot] = (index + 1) & 0xff; @@ -464,7 +464,7 @@ class HashIndexTable { } [[nodiscard]] int32_t get(const std::string& name) const { - int32_t slot = hashSlotFor(name); + const int32_t slot = hashSlotFor(name); // subtract 1, 0 stands for empty return (_hashTable[slot] & 0xff) - 1; } @@ -473,11 +473,11 @@ class HashIndexTable { [[nodiscard]] int32_t stringHash(const std::string& s) const { // this is not a proper hash, but sufficient for the benchmark, // and very portable! - return s.size() * 1402589; + return static_cast(s.size()) * 1402589; } [[nodiscard]] int32_t hashSlotFor(const std::string& element) const { - return stringHash(element) & _hashTable.size() - 1; + return stringHash(element) & static_cast(_hashTable.size()) - 1; } }; @@ -526,7 +526,7 @@ class JsonArray : public JsonValue { [[nodiscard]] size_t size() const { return _values.size(); } - [[nodiscard]] const JsonValue* get(int index) const { + [[nodiscard]] const JsonValue* get(int32_t index) const { return *_values.at(index); } @@ -543,10 +543,13 @@ class JsonLiteral : public JsonValue { bool _isFalse; JsonLiteral(string value, bool isNull, bool isTrue, bool isFalse) - : _value(value), _isNull(isNull), _isTrue(isTrue), _isFalse(isFalse) {} + : _value(std::move(value)), + _isNull(isNull), + _isTrue(isTrue), + _isFalse(isFalse) {} public: - JsonLiteral(string value) + explicit JsonLiteral(const string& value) : _value(value), _isNull(value == "null"), _isTrue(value == "true"), @@ -577,7 +580,7 @@ class JsonNumber : public JsonValue { string _string; public: - JsonNumber(string string) : _string(string) { + explicit JsonNumber(const string& string) : _string(string) { if (string.empty()) { throw Error("value is null"); } @@ -593,8 +596,8 @@ class JsonObject : public JsonValue { Vector _values{}; HashIndexTable _table{}; - int32_t indexOf(string name) const { - int32_t index = _table.get(name); + [[nodiscard]] int32_t indexOf(const string& name) const { + const int32_t index = _table.get(name); if (index != -1 && name == *_names.at(index)) { return index; } @@ -605,30 +608,30 @@ class JsonObject : public JsonValue { JsonObject() = default; ~JsonObject() override { _values.destroyValues(); } - void add(string name, const JsonValue* value) { + void add(const string& name, const JsonValue* value) { if (name.empty()) { throw Error("name is null"); } if (value == nullptr) { throw Error("value is null"); } - _table.add(name, _names.size()); + _table.add(name, static_cast(_names.size())); _names.append(name); _values.append(value); } - const JsonValue* get(string name) const { + [[nodiscard]] const JsonValue* get(const string& name) const { if (name.empty()) { throw Error("name is null"); } - int32_t index = indexOf(name); + const int32_t index = indexOf(name); return index == -1 ? nullptr : *_values.at(index); } [[nodiscard]] size_t size() const { return _names.size(); } [[nodiscard]] bool isEmpty() const { return _names.isEmpty(); } [[nodiscard]] bool isObject() const override { return true; } - const JsonObject* asObject() const override { return this; } + [[nodiscard]] const JsonObject* asObject() const override { return this; } }; class JsonString : public JsonValue { @@ -636,7 +639,7 @@ class JsonString : public JsonValue { string _string; public: - JsonString(string string) : _string(string) {} + explicit JsonString(string string) : _string(std::move(string)) {} [[nodiscard]] bool isString() const override { return true; } }; @@ -649,14 +652,17 @@ class ParseException : virtual public std::exception { string _what; public: - ParseException(string message, size_t offset, int32_t line, int32_t column) + ParseException(const string& message, + size_t offset, + int32_t line, + int32_t column) : _offset(offset), _line(line), _column(column), _what(message + " at " + std::to_string(line) + ":" + std::to_string(column)) {} - [[nodiscard]] int32_t getOffset() const { return _offset; } + [[nodiscard]] size_t getOffset() const { return _offset; } [[nodiscard]] int32_t getLine() const { return _line; } [[nodiscard]] int32_t getColumn() const { return _column; } [[nodiscard]] const char* what() const noexcept override { @@ -670,42 +676,49 @@ class JsonPureStringParser { size_t _index{SIZE_MAX}; int32_t _line{1}; int32_t _column{0}; - string _current{""}; - string _captureBuffer{""}; + string _current{}; + string _captureBuffer{}; size_t _captureStart{SIZE_MAX}; const JsonValue* readValue() { if (_current == "n") { return readNull(); - } else if (_current == "t") { + } + if (_current == "t") { return readTrue(); - } else if (_current == "f") { + } + if (_current == "f") { return readFalse(); - } else if (_current == "\"") { + } + if (_current == "\"") { return readString(); - } else if (_current == "[") { + } + if (_current == "[") { return readArray(); - } else if (_current == "{") { + } + if (_current == "{") { return readObject(); - } else if (_current == "-" || _current == "0" || _current == "1" || - _current == "2" || _current == "3" || _current == "4" || - _current == "5" || _current == "6" || _current == "7" || - _current == "8" || _current == "9") { + } + if (_current == "-" || _current == "0" || _current == "1" || + _current == "2" || _current == "3" || _current == "4" || + _current == "5" || _current == "6" || _current == "7" || + _current == "8" || _current == "9") { return readNumber(); - } else - throw expected("value"); + } + + throw expected("value"); } JsonObject* readObject() { read(); - JsonObject* object = new JsonObject(); + auto* object = new JsonObject(); skipWhiteSpace(); if (readChar("}")) { return object; } do { skipWhiteSpace(); - string name = readName(); + const string name = readName(); skipWhiteSpace(); if (!readChar(":")) { throw expected("':'"); @@ -730,7 +743,7 @@ class JsonPureStringParser { JsonArray* readArray() { read(); - JsonArray* array = new JsonArray(); + auto* array = new JsonArray(); skipWhiteSpace(); if (readChar("]")) { return array; @@ -772,7 +785,7 @@ class JsonPureStringParser { return JsonLiteral::createFalse(); } - void readRequiredChar(string ch) { + void readRequiredChar(const string& ch) { if (!readChar(ch)) { throw expected("'" + ch + "'"); } @@ -799,27 +812,28 @@ class JsonPureStringParser { void readEscape() { read(); - if (_current == "\"" || _current == "/" || _current == "\\") + if (_current == "\"" || _current == "/" || _current == "\\") { _captureBuffer += _current; - else if (_current == "b") + } else if (_current == "b") { _captureBuffer += "\b"; - else if (_current == "f") + } else if (_current == "f") { _captureBuffer += "\f"; - else if (_current == "n") + } else if (_current == "n") { _captureBuffer += "\n"; - else if (_current == "r") + } else if (_current == "r") { _captureBuffer += "\r"; - else if (_current == "t") + } else if (_current == "t") { _captureBuffer += "\t"; - else + } else { throw expected("valid escape sequence"); + } read(); } const JsonValue* readNumber() { startCapture(); readChar("-"); - string firstDigit = _current; + const string firstDigit = _current; if (!readDigit()) { throw expected("digit"); } @@ -861,7 +875,7 @@ class JsonPureStringParser { return true; } - bool readChar(string ch) { + bool readChar(const string& ch) { if (_current != ch) { return false; } @@ -899,15 +913,15 @@ class JsonPureStringParser { void startCapture() { _captureStart = _index; } void pauseCapture() { - size_t _end = _current == "" ? _index : _index - 1; + const size_t _end = _current.empty() ? _index : _index - 1; _captureBuffer += _input.substr(_captureStart, _end - _captureStart + 1); _captureStart = -1; } string endCapture() { - size_t _end = _current == "" ? _index : _index - 1; + const size_t _end = _current.empty() ? _index : _index - 1; string captured; - if ("" == _captureBuffer) { + if (_captureBuffer.empty()) { captured = _input.substr(_captureStart, _end - _captureStart + 1); } else { _captureBuffer += _input.substr(_captureStart, _end - _captureStart + 1); @@ -918,7 +932,7 @@ class JsonPureStringParser { return captured; } - ParseException expected(string expected) { + ParseException expected(const string& expected) { if (isEndOfText()) { return error("Unexpected end of input"); } @@ -926,8 +940,8 @@ class JsonPureStringParser { return error("Expected " + expected); } - ParseException error(string message) { - return ParseException(message, _index, _line, _column - 1); + [[nodiscard]] ParseException error(const string& message) const { + return {message, _index, _line, _column - 1}; } bool isWhiteSpace() { @@ -942,10 +956,10 @@ class JsonPureStringParser { "9" == _current; } - bool isEndOfText() { return _current == ""; } + bool isEndOfText() { return _current.empty(); } public: - JsonPureStringParser(string string) : _input(string) {} + explicit JsonPureStringParser(string string) : _input(std::move(string)) {} const JsonValue* parse() { read(); @@ -973,14 +987,14 @@ class Json : public Benchmark { if (!result->isObject()) { return false; } - auto* resultObject = result->asObject(); + const auto* resultObject = result->asObject(); if (!resultObject->get("head")->isObject()) { return false; } if (!resultObject->get("operations")->isArray()) { return false; } - auto* resultArray = resultObject->get("operations")->asArray(); + const auto* resultArray = resultObject->get("operations")->asArray(); return resultArray->size() == 156; } @@ -990,4 +1004,4 @@ class Json : public Benchmark { delete result; return doesVerify; } -}; \ No newline at end of file +}; From a68477d2acea82330f23d40eb736d9d2566466b9 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 9 Jan 2024 16:17:32 +0000 Subject: [PATCH 17/40] [C++] Remove remaining *Ptr methods and solve it by returning pointers from the methods so that they can be null even when T is a value type - also hange order in signature to matchthe other languages Signed-off-by: Stefan Marr --- benchmarks/C++/src/deltablue.h | 10 ++++++---- benchmarks/C++/src/som/dictionary.h | 23 +++++------------------ benchmarks/C++/src/som/vector.h | 13 +++---------- 3 files changed, 14 insertions(+), 32 deletions(-) diff --git a/benchmarks/C++/src/deltablue.h b/benchmarks/C++/src/deltablue.h index 4a0cef2a..c1638b50 100644 --- a/benchmarks/C++/src/deltablue.h +++ b/benchmarks/C++/src/deltablue.h @@ -40,7 +40,7 @@ class Strength { public: explicit Strength(const Sym* const symbolicValue) - : _arithmeticValue(_strengthTable->at(symbolicValue)), + : _arithmeticValue(*_strengthTable->at(symbolicValue)), _symbolicValue(symbolicValue) {} bool sameAs(const Strength* const s) const { @@ -66,7 +66,7 @@ class Strength { [[nodiscard]] int32_t getArithmeticValue() const { return _arithmeticValue; } static const Strength* of(const Sym* const strength) { - return _strengthConstant->atPtr(strength); + return *_strengthConstant->at(strength); } static const Strength* absoluteWeakest(); static const Strength* required(); @@ -686,14 +686,16 @@ class Planner { planner.change(scale, 5); for (int32_t i = 0; i < n - 1; ++i) { - if (dests.at(i)->getValue() != (i + 1) * 5 + 1000) { + Variable* di = *dests.at(i); + if (di->getValue() != (i + 1) * 5 + 1000) { throw Error("Projection test 3 failed!"); } } planner.change(offset, 2000); for (int32_t i = 0; i < n - 1; ++i) { - if (dests.at(i)->getValue() != (i + 1) * 5 + 2000) { + Variable* di = *dests.at(i); + if (di->getValue() != (i + 1) * 5 + 2000) { throw Error("Projection test 4 failed!"); } } diff --git a/benchmarks/C++/src/som/dictionary.h b/benchmarks/C++/src/som/dictionary.h index a49e20a4..56ad916c 100644 --- a/benchmarks/C++/src/som/dictionary.h +++ b/benchmarks/C++/src/som/dictionary.h @@ -88,31 +88,18 @@ class Dictionary { return false; } - V atPtr(const CustomHash* key) const { - const int32_t h = hash(key); - Entry* e = getBucket(h); - - while (e != nullptr) { - if (e->match(h, key)) { - return e->_value; - } - e = e->_next; - } - return nullptr; - } - - V at(const CustomHash* key) const { + V* at(const CustomHash* key) const { const int32_t h = this->hash(key); Entry* e = getBucket(h); while (e != nullptr) { if (e->match(h, key)) { - return e->_value; + return &e->_value; } e = e->_next; } // Return a default-constructed V if the key is not found - return V(); + return nullptr; } void atPut(const CustomHash* const key, const V& value) { @@ -233,13 +220,13 @@ class Dictionary { if (current->_next == nullptr) { _buckets[current->_hash & (oldCapacity - 1)] = current; } else { - splitBucket(i, current, oldCapacity); + splitBucket(oldCapacity, i, current); } } } } - void splitBucket(int32_t idx, Entry* head, int32_t oldCapacity) { + void splitBucket(int32_t oldCapacity, int32_t idx, Entry* head) { Entry* loHead = nullptr; Entry* loTail = nullptr; Entry* hiHead = nullptr; diff --git a/benchmarks/C++/src/som/vector.h b/benchmarks/C++/src/som/vector.h index 07e6e757..7c6f7402 100644 --- a/benchmarks/C++/src/som/vector.h +++ b/benchmarks/C++/src/som/vector.h @@ -84,7 +84,7 @@ class Vector { explicit Vector(size_t size) : storage(new E[size]), _capacity(size) {} - Vector() : Vector(50) {} // NOLINT + explicit Vector() : Vector(50) {} // NOLINT ~Vector() { delete[] storage; } @@ -94,18 +94,11 @@ class Vector { } } - [[nodiscard]] E atPtr(size_t idx) const { + [[nodiscard]] E* at(size_t idx) const { if (idx >= _lastIdx - _firstIdx) { return nullptr; } - return storage[_firstIdx + idx]; - } - - [[nodiscard]] E at(size_t idx) const { - if (idx >= _lastIdx - _firstIdx) { - return E(); - } - return storage[_firstIdx + idx]; + return &storage[_firstIdx + idx]; } void atPut(size_t idx, const E& val) { From 8b53a732686a65c0ce16dc16d8999bb8e2195ffd Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 9 Jan 2024 17:56:37 +0000 Subject: [PATCH 18/40] [C++] Added Havlak port by Hugo Jenningros Signed-off-by: Stefan Marr --- benchmarks/C++/src/Havlak.cpp | 34 ++++ benchmarks/C++/src/Havlak.h | 21 ++ benchmarks/C++/src/havlak/BasicBlock.cpp | 34 ++++ benchmarks/C++/src/havlak/BasicBlock.h | 29 +++ benchmarks/C++/src/havlak/BasicBlockEdge.cpp | 16 ++ benchmarks/C++/src/havlak/BasicBlockEdge.h | 21 ++ .../C++/src/havlak/ControlFlowGraph.cpp | 44 +++++ benchmarks/C++/src/havlak/ControlFlowGraph.h | 28 +++ .../C++/src/havlak/HavlakLoopFinder.cpp | 184 ++++++++++++++++++ benchmarks/C++/src/havlak/HavlakLoopFinder.h | 65 +++++++ .../C++/src/havlak/LoopStructureGraph.cpp | 54 +++++ .../C++/src/havlak/LoopStructureGraph.h | 28 +++ benchmarks/C++/src/havlak/LoopTesterApp.cpp | 103 ++++++++++ benchmarks/C++/src/havlak/LoopTesterApp.h | 31 +++ benchmarks/C++/src/havlak/SimpleLoop.cpp | 67 +++++++ benchmarks/C++/src/havlak/SimpleLoop.h | 39 ++++ benchmarks/C++/src/havlak/UnionFindNode.cpp | 56 ++++++ benchmarks/C++/src/havlak/UnionFindNode.h | 33 ++++ 18 files changed, 887 insertions(+) create mode 100644 benchmarks/C++/src/Havlak.cpp create mode 100644 benchmarks/C++/src/Havlak.h create mode 100644 benchmarks/C++/src/havlak/BasicBlock.cpp create mode 100644 benchmarks/C++/src/havlak/BasicBlock.h create mode 100644 benchmarks/C++/src/havlak/BasicBlockEdge.cpp create mode 100644 benchmarks/C++/src/havlak/BasicBlockEdge.h create mode 100644 benchmarks/C++/src/havlak/ControlFlowGraph.cpp create mode 100644 benchmarks/C++/src/havlak/ControlFlowGraph.h create mode 100644 benchmarks/C++/src/havlak/HavlakLoopFinder.cpp create mode 100644 benchmarks/C++/src/havlak/HavlakLoopFinder.h create mode 100644 benchmarks/C++/src/havlak/LoopStructureGraph.cpp create mode 100644 benchmarks/C++/src/havlak/LoopStructureGraph.h create mode 100644 benchmarks/C++/src/havlak/LoopTesterApp.cpp create mode 100644 benchmarks/C++/src/havlak/LoopTesterApp.h create mode 100644 benchmarks/C++/src/havlak/SimpleLoop.cpp create mode 100644 benchmarks/C++/src/havlak/SimpleLoop.h create mode 100644 benchmarks/C++/src/havlak/UnionFindNode.cpp create mode 100644 benchmarks/C++/src/havlak/UnionFindNode.h diff --git a/benchmarks/C++/src/Havlak.cpp b/benchmarks/C++/src/Havlak.cpp new file mode 100644 index 00000000..c7d003ff --- /dev/null +++ b/benchmarks/C++/src/Havlak.cpp @@ -0,0 +1,34 @@ +#include "Havlak.h" + +namespace havlak { + bool Havlak::innerBenchmarkLoop(int innerIterations) { + bool result = verifyResult((make_shared())->main( + innerIterations, 50, 10 /* was 100 */, 10, 5), innerIterations); + return result; + } + + bool Havlak::verifyResult(any result, int innerIterations) { + vector r = any_cast>(result); + if (innerIterations == 15000) { return r[0] == 46602 && r[1] == 5213; } + if (innerIterations == 1500) { return r[0] == 6102 && r[1] == 5213; } + if (innerIterations == 150) { return r[0] == 2052 && r[1] == 5213; } + if (innerIterations == 15) { return r[0] == 1647 && r[1] == 5213; } + if (innerIterations == 1) { return r[0] == 1605 && r[1] == 5213; } + + + cout << "No verification result for " << innerIterations << " found" << endl; + cout << "Result is: " << r[0] << ", " << r[1] << endl; + + return false; + } + + any Havlak::benchmark() { + throw Error("Should never be reached"); + } + + + bool Havlak::verifyResult(any result) { + (void)result; + throw Error("Should never be reached"); + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/Havlak.h b/benchmarks/C++/src/Havlak.h new file mode 100644 index 00000000..c8be3718 --- /dev/null +++ b/benchmarks/C++/src/Havlak.h @@ -0,0 +1,21 @@ +#ifndef HAVLAK +#define HAVLAK + +#include "havlak/LoopTesterApp.h" +#include "Benchmark.h" +#include "som/Error.cpp" + +using namespace std; + +namespace havlak { + class Havlak : public Benchmark { + + public: + bool innerBenchmarkLoop(int innerIterations) override; + bool verifyResult(any result, int innerIterations); + any benchmark() override; + bool verifyResult(any result) override; + }; +} + +#endif //HAVLAK \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/BasicBlock.cpp b/benchmarks/C++/src/havlak/BasicBlock.cpp new file mode 100644 index 00000000..f7e76322 --- /dev/null +++ b/benchmarks/C++/src/havlak/BasicBlock.cpp @@ -0,0 +1,34 @@ +#include "BasicBlock.h" + +namespace havlak { + + BasicBlock::BasicBlock(int name) : CustomHash(){ + _name = name; + _inEdges = make_shared>>(2); + _outEdges = make_shared>>(2); + } + + shared_ptr>> BasicBlock::getInEdges() { + return _inEdges; + } + + shared_ptr>> BasicBlock::getOutEdges() { + return _outEdges; + } + + int BasicBlock::getNumPred() { + return _inEdges->size(); + } + + void BasicBlock::addOutEdge(shared_ptr to) { + _outEdges->append(to); + } + + void BasicBlock::addInEdge(shared_ptr from) { + _inEdges->append(from); + } + + int BasicBlock::customHash() { + return _name; + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/BasicBlock.h b/benchmarks/C++/src/havlak/BasicBlock.h new file mode 100644 index 00000000..69e14987 --- /dev/null +++ b/benchmarks/C++/src/havlak/BasicBlock.h @@ -0,0 +1,29 @@ +#ifndef BASICBLOCK +#define BASICBLOCK + +#include "../som/Vector.cpp" +#include +#include "../som/Dictionary.cpp" +using namespace std; + +namespace havlak { + class BasicBlock: public CustomHash { + private: + shared_ptr>> _inEdges; + shared_ptr>> _outEdges; + int _name; + + public: + + BasicBlock(int name); + shared_ptr>> getInEdges(); + shared_ptr>> getOutEdges(); + int getNumPred(); + void addOutEdge(shared_ptr to); + void addInEdge(shared_ptr from); + int customHash() override; + + }; +} + +#endif //BASICBLOCK \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/BasicBlockEdge.cpp b/benchmarks/C++/src/havlak/BasicBlockEdge.cpp new file mode 100644 index 00000000..64eb8e15 --- /dev/null +++ b/benchmarks/C++/src/havlak/BasicBlockEdge.cpp @@ -0,0 +1,16 @@ +#include "BasicBlock.h" +#include "ControlFlowGraph.h" + +using namespace std; + +namespace havlak { + + BasicBlockEdge::BasicBlockEdge(shared_ptr cfg, int fromName, int toName) { + _from = cfg->createNode(fromName); + _to = cfg->createNode(toName); + + _from->addOutEdge(_to); + _to->addInEdge(_from); + } + +} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/BasicBlockEdge.h b/benchmarks/C++/src/havlak/BasicBlockEdge.h new file mode 100644 index 00000000..a5d47e93 --- /dev/null +++ b/benchmarks/C++/src/havlak/BasicBlockEdge.h @@ -0,0 +1,21 @@ +#ifndef BASICBLOCKEDGE +#define BASICBLOCKEDGE + +#include "BasicBlock.h" + +using namespace std; + +namespace havlak { + class ControlFlowGraph; + + class BasicBlockEdge : public enable_shared_from_this { + private: + shared_ptr _from; + shared_ptr _to; + + public: + BasicBlockEdge(shared_ptr cfg, int fromName, int toName); + }; +} + +#endif //BASICBLOCKEDGE \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/ControlFlowGraph.cpp b/benchmarks/C++/src/havlak/ControlFlowGraph.cpp new file mode 100644 index 00000000..be383035 --- /dev/null +++ b/benchmarks/C++/src/havlak/ControlFlowGraph.cpp @@ -0,0 +1,44 @@ +#include "ControlFlowGraph.h" + +#include + +namespace havlak { + + ControlFlowGraph::ControlFlowGraph() { + _startNode = nullptr; + _basicBlockMap = make_shared>>(); + _edgeList = make_shared>>(); + } + + shared_ptr ControlFlowGraph::createNode(int name) { + shared_ptr node; + if (_basicBlockMap != nullptr && _basicBlockMap->atPtr(name) != nullptr) { + node = _basicBlockMap->atPtr(name); + } else { + node = make_shared(name); + _basicBlockMap->atPut(name, node); + } + + if (getNumNodes() == 1) { + _startNode = node; + } + return node; + } + + void ControlFlowGraph::addEdge(shared_ptr edge) { + _edgeList->append(edge); + } + + int ControlFlowGraph::getNumNodes() { + return _basicBlockMap->size(); + } + + shared_ptr ControlFlowGraph::getStartBasicBlock() { + return _startNode; + } + + shared_ptr>> ControlFlowGraph::getBasicBlocks() { + return _basicBlockMap; + } + +} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/ControlFlowGraph.h b/benchmarks/C++/src/havlak/ControlFlowGraph.h new file mode 100644 index 00000000..a34d3632 --- /dev/null +++ b/benchmarks/C++/src/havlak/ControlFlowGraph.h @@ -0,0 +1,28 @@ +#ifndef CONTROLFLOWGRAPH +#define CONTROLFLOWGRAPH + +#include "BasicBlock.h" +#include "BasicBlockEdge.h" +#include "../som/Vector.cpp" +using namespace std; + +namespace havlak { + + class ControlFlowGraph { + private: + shared_ptr>> _basicBlockMap; + shared_ptr _startNode; + shared_ptr>> _edgeList; + + public: + ControlFlowGraph(); + shared_ptr createNode(int name); + void addEdge(shared_ptr edge); + int getNumNodes(); + shared_ptr getStartBasicBlock(); + shared_ptr>> getBasicBlocks(); + + }; +} + +#endif //CONTROLFLOWGRAPH diff --git a/benchmarks/C++/src/havlak/HavlakLoopFinder.cpp b/benchmarks/C++/src/havlak/HavlakLoopFinder.cpp new file mode 100644 index 00000000..b2ec8fd8 --- /dev/null +++ b/benchmarks/C++/src/havlak/HavlakLoopFinder.cpp @@ -0,0 +1,184 @@ + +#include "HavlakLoopFinder.h" + +namespace havlak { + + bool HavlakLoopFinder::isAncestor(int w, int v) { + return w <= v && v <= _last[w]; + } + + int HavlakLoopFinder::doDFS(shared_ptr currentNode, int current) { + _nodes[current]->initNode(currentNode, current); + _number->atPut(currentNode, current); + int lastId = current; + shared_ptr>> outerBlocks = currentNode->getOutEdges(); + for (int i = 0; i < outerBlocks->size(); i++) { + shared_ptr target = outerBlocks->at(i); + if (_number->at(target) == UNVISITED) { + lastId = doDFS(target, lastId + 1); + } + } + + _last[current] = lastId; + return lastId; + } + + void HavlakLoopFinder::initAllNodes() { + _cfg->getBasicBlocks()->forEach([&](shared_ptr bb) -> void { + _number->atPut(bb, UNVISITED); + }); + doDFS(_cfg->getStartBasicBlock(), 0); + } + + void HavlakLoopFinder::identifyEdges(int size) { + for (int w = 0; w < size; w++) { + _header[w] = 0; + _type[w] = BB_NONHEADER; + + shared_ptr nodeW = _nodes[w]->getBb(); + if (nodeW == nullptr) { + _type[w] = BB_DEAD; + } else { + processEdges(nodeW, w); + } + } + } + + void HavlakLoopFinder::processEdges(shared_ptr nodeW, int w) { + if (nodeW->getNumPred() > 0) { + nodeW->getInEdges()->forEach([&](shared_ptr nodeV) -> void { + int v = _number->at(nodeV); + if (v != UNVISITED) { + if (isAncestor(w, v)) { + _backPreds->at(w)->append(v); + } else { + _nonBackPreds->at(w).insert(v); + } + } + }); + } + } + + void HavlakLoopFinder::stepEProcessNonBackPreds(int w, shared_ptr>> nodePool, shared_ptr>> workList, shared_ptr x) { + for (int iter : _nonBackPreds->at(x->getDfsNumber())) { + shared_ptr y = _nodes[iter]; + shared_ptr ydash = y->findSet(); + + if (!isAncestor(w, ydash->getDfsNumber())) { + _type[w] = BB_IRREDUCIBLE; + _nonBackPreds->at(w).insert(ydash->getDfsNumber()); + } else { + if (ydash->getDfsNumber() != w) { + if (!nodePool->hasSome([&](shared_ptr e) -> bool { + return e == ydash; + })) { + workList->append(ydash); + nodePool->append(ydash); + } + } + } + } + } + + + void HavlakLoopFinder::setLoopAttributes(int w, shared_ptr>> nodePool, shared_ptr loop) { + _nodes[w]->setLoop(loop); + + nodePool->forEach([&](shared_ptr node) -> void { + _header[node->getDfsNumber()] = w; + node->unionSet(_nodes[w]); + + // Nested loops are not added, but linked together. + if (node->getLoop() != nullptr) { + node->getLoop()->setParent(loop); + } else { + loop->addNode(node->getBb()); + } + }); + } + + void HavlakLoopFinder::stepD(int w, shared_ptr>> nodePool) { + + _backPreds->at(w)->forEach([&](int v) -> void { + if (v != w) { + nodePool->append(_nodes[v]->findSet()); + } else { + _type[w] = BB_SELF; + } + }); + } + + + + HavlakLoopFinder::HavlakLoopFinder(shared_ptr cfg, shared_ptr lsg) { + _cfg = cfg; + _lsg = lsg; + } + + void HavlakLoopFinder::findLoops() { + if (_cfg->getStartBasicBlock() == nullptr) { + return; + } + + int size = _cfg->getNumNodes(); + + _nonBackPreds->removeAll(); + _backPreds->removeAll(); + _number->removeAll(); + if (size > _maxSize) { + _header = new int[size]; + _type = new BasicBlockClass[size]; + _last = new int[size]; + _nodes = new shared_ptr[size]; + _maxSize = size; + } + + for (int i = 0; i < size; ++i) { + _nodes[i] = make_shared(); + _backPreds->append(make_shared>()); + } + + initAllNodes(); + identifyEdges(size); + + // Start node is root of all other loops. + _header[0] = 0; + for (int w = size - 1; w >= 0; w--) { + // this is 'P' in Havlak's paper + shared_ptr>> nodePool = make_shared>>(); + + shared_ptr nodeW = _nodes[w]->getBb(); + if (nodeW != nullptr) { + stepD(w, nodePool); + + // Copy nodePool to workList. + // + shared_ptr>> workList = make_shared>>(); + nodePool->forEach([&](shared_ptr niter) -> void { + workList->append(niter); + }); + + if (nodePool->size() != 0) { + _type[w] = BB_REDUCIBLE; + } + + // work the list... + // + while (!workList->isEmpty()) { + shared_ptr x = workList->removeFirst(); + + int nonBackSize = _nonBackPreds->at(x->getDfsNumber()).size(); + if (nonBackSize > MAXNONBACKPREDS) { + return; + } + stepEProcessNonBackPreds(w, nodePool, workList, x); + } + + if ((nodePool->size() > 0) || (_type[w] == BB_SELF)) { + shared_ptr loop = _lsg->createNewLoop(nodeW, _type[w] != BB_IRREDUCIBLE); + setLoopAttributes(w, nodePool, loop); + } + } + } // Step c + } // findLoops +} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/HavlakLoopFinder.h b/benchmarks/C++/src/havlak/HavlakLoopFinder.h new file mode 100644 index 00000000..cf1b2947 --- /dev/null +++ b/benchmarks/C++/src/havlak/HavlakLoopFinder.h @@ -0,0 +1,65 @@ +#ifndef HAVLAKLOOPFINDER +#define HAVLAKLOOPFINDER + +#include "ControlFlowGraph.h" +#include "LoopStructureGraph.h" +#include "UnionFindNode.h" +#include +#include +#include +#include "../som/IdentityDictionary.cpp" + +using namespace std; + +namespace havlak { + class HavlakLoopFinder { + private: + + enum BasicBlockClass { + BB_TOP, // uninitialized + BB_NONHEADER, // a regular BB + BB_REDUCIBLE, // reducible loop + BB_SELF, // single BB loop + BB_IRREDUCIBLE, // irreducible loop + BB_DEAD, // a dead BB + BB_LAST // Sentinel + }; + + shared_ptr _cfg; // Control Flow Graph + shared_ptr _lsg; // Loop Structure Graph + + static constexpr int UNVISITED = numeric_limits::max(); + static constexpr int MAXNONBACKPREDS = 32 * 1024; + + shared_ptr>> _nonBackPreds = make_shared>>() ; + shared_ptr>>> _backPreds = make_shared>>>(); + shared_ptr> _number = make_shared>(); + + int _maxSize = 0; + int* _header; + BasicBlockClass* _type; + int* _last; + shared_ptr* _nodes; + + public: + HavlakLoopFinder(shared_ptr cfg, shared_ptr lsg); + void findLoops(); + + private: + bool isAncestor(int w, int v); + int doDFS(shared_ptr currentNode, int current); + void initAllNodes(); + void identifyEdges(int size); + void processEdges(shared_ptr nodeW, int w); + void stepEProcessNonBackPreds(int w, shared_ptr>> nodePool, shared_ptr>> workList, shared_ptr x); + + + void setLoopAttributes(int w, shared_ptr>> nodePool, shared_ptr loop); + void stepD(int w, shared_ptr>> nodePool); + + + + }; +} + +#endif //HAVLAKLOOPFINDER \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/LoopStructureGraph.cpp b/benchmarks/C++/src/havlak/LoopStructureGraph.cpp new file mode 100644 index 00000000..44009a54 --- /dev/null +++ b/benchmarks/C++/src/havlak/LoopStructureGraph.cpp @@ -0,0 +1,54 @@ +#include "LoopStructureGraph.h" + +using namespace std; + +namespace havlak { + + + LoopStructureGraph::LoopStructureGraph() { + _loopCounter = 0; + _loops = make_shared>>(); + _root = make_shared(nullptr, true); + _root->setNestingLevel(0); + _root->setCounter(_loopCounter); + _loopCounter += 1; + _loops->append(_root); + } + + shared_ptr LoopStructureGraph::createNewLoop(shared_ptr bb, bool isReducible) { + shared_ptr loop = make_shared(bb, isReducible); + loop->setCounter(_loopCounter); + _loopCounter += 1; + _loops->append(loop); + return loop; + } + + void LoopStructureGraph::calculateNestingLevel() { + // link up all 1st level loops to artificial root node. + _loops->forEach([&](shared_ptr liter) -> void { + if (!liter->isRoot()) { + if (liter->getParent() == nullptr) { + liter->setParent(_root); + } + } + }); + + // recursively traverse the tree and assign levels. + calculateNestingLevelRec(_root, 0); + } + + void LoopStructureGraph::calculateNestingLevelRec(shared_ptr loop, int depth) { + loop->setDepthLevel(depth); + for (auto liter : loop->getChildren()) { + calculateNestingLevelRec(liter, depth + 1); + + loop->setNestingLevel(std::max(loop->getNestingLevel(), + 1 + liter->getNestingLevel())); + } + } + + int LoopStructureGraph::getNumLoops() { + return _loops->size(); + } + +} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/LoopStructureGraph.h b/benchmarks/C++/src/havlak/LoopStructureGraph.h new file mode 100644 index 00000000..9efce91d --- /dev/null +++ b/benchmarks/C++/src/havlak/LoopStructureGraph.h @@ -0,0 +1,28 @@ +#ifndef LOOPSTRUCTUREGRAPH +#define LOOPSTRUCTUREGRAPH + +#include +#include "SimpleLoop.h" +#include "../som/Vector.cpp" + +using namespace std; + +namespace havlak { + class LoopStructureGraph { + private: + shared_ptr _root; + shared_ptr>> _loops; + int _loopCounter; + + public: + + LoopStructureGraph(); + + shared_ptr createNewLoop(shared_ptr bb, bool isReducible); + void calculateNestingLevel(); + void calculateNestingLevelRec(shared_ptr loop, int depth); + int getNumLoops(); + }; +} + +#endif //LOOPSTRUCTUREGRAPH \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/LoopTesterApp.cpp b/benchmarks/C++/src/havlak/LoopTesterApp.cpp new file mode 100644 index 00000000..24502a35 --- /dev/null +++ b/benchmarks/C++/src/havlak/LoopTesterApp.cpp @@ -0,0 +1,103 @@ +#include "LoopTesterApp.h" + +using namespace std; + +namespace havlak { + + int LoopTesterApp::buildDiamond(int start) { + int bb0 = start; + _cfg->addEdge(make_shared(_cfg, bb0, bb0 + 1)); + _cfg->addEdge(make_shared(_cfg, bb0, bb0 + 2)); + _cfg->addEdge(make_shared(_cfg, bb0 + 1, bb0 + 3)); + _cfg->addEdge(make_shared(_cfg, bb0 + 2, bb0 + 3)); + + return bb0 + 3; + } + + void LoopTesterApp::buildConnect(int start, int end) { + _cfg->addEdge(make_shared(_cfg, start, end)); + } + + int LoopTesterApp::buildStraight(int start, int n) { + for (int i = 0; i < n; i++) { + buildConnect(start + i, start + i + 1); + } + return start + n; + } + + int LoopTesterApp::buildBaseLoop(int from) { + int header = buildStraight(from, 1); + int diamond1 = buildDiamond(header); + int d11 = buildStraight(diamond1, 1); + int diamond2 = buildDiamond(d11); + int footer = buildStraight(diamond2, 1); + buildConnect(diamond2, d11); + buildConnect(diamond1, header); + buildConnect(footer, from); + footer = buildStraight(footer, 1); + return footer; + } + + void LoopTesterApp::constructSimpleCFG() { + _cfg->createNode(0); + buildBaseLoop(0); + _cfg->createNode(1); + + _cfg->addEdge(make_shared(_cfg, 0, 2)); + } + + LoopTesterApp::LoopTesterApp() { + _cfg = make_shared(); + _lsg = make_shared(); + _cfg->createNode(0); + + } + + vector LoopTesterApp::main(int numDummyLoops, int findLoopIterations, int parLoops, + int pparLoops, int ppparLoops) { + constructSimpleCFG(); + addDummyLoops(numDummyLoops); + constructCFG(parLoops, pparLoops, ppparLoops); + findLoops(_lsg); + for (int i = 0; i < findLoopIterations; i++) { + findLoops(make_shared()); + } + + _lsg->calculateNestingLevel(); + vector result = {_lsg->getNumLoops(), _cfg->getNumNodes()}; + return result; + } + + void LoopTesterApp::constructCFG(int parLoops, int pparLoops, int ppparLoops) { + int n = 2; + + for (int parlooptrees = 0; parlooptrees < parLoops; parlooptrees++) { + _cfg->createNode(n + 1); + buildConnect(2, n + 1); + n += 1; + + for (int i = 0; i < pparLoops; i++) { + int top = n; + n = buildStraight(n, 1); + for (int j = 0; j < ppparLoops; j++) { + n = buildBaseLoop(n); + } + int bottom = buildStraight(n, 1); + buildConnect(n, top); + n = bottom; + } + buildConnect(n, 1); + } + } + + void LoopTesterApp::addDummyLoops(int numDummyLoops) { + for (int dummyloop = 0; dummyloop < numDummyLoops; dummyloop++) { + findLoops(_lsg); + } + } + + void LoopTesterApp::findLoops(shared_ptr loopStructure) { + shared_ptr finder = make_shared(_cfg, loopStructure); + finder->findLoops(); + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/LoopTesterApp.h b/benchmarks/C++/src/havlak/LoopTesterApp.h new file mode 100644 index 00000000..95b1aeb4 --- /dev/null +++ b/benchmarks/C++/src/havlak/LoopTesterApp.h @@ -0,0 +1,31 @@ +#include "ControlFlowGraph.h" +#include "LoopStructureGraph.h" +#include "HavlakLoopFinder.h" +#include +#include + +using namespace std; + +namespace havlak { + class LoopTesterApp { + + private: + + shared_ptr _cfg; + shared_ptr _lsg; + + int buildDiamond(int start); + void buildConnect(int start, int end); + int buildStraight(int start, int n); + int buildBaseLoop(int from); + void constructSimpleCFG(); + + public: + LoopTesterApp(); + vector main(int numDummyLoops, int findLoopIterations, int parLoops, + int pparLoops, int ppparLoops); + void constructCFG(int parLoops, int pparLoops, int ppparLoops); + void addDummyLoops(int numDummyLoops); + void findLoops(shared_ptr loopStructure); + }; +} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/SimpleLoop.cpp b/benchmarks/C++/src/havlak/SimpleLoop.cpp new file mode 100644 index 00000000..3476dc3f --- /dev/null +++ b/benchmarks/C++/src/havlak/SimpleLoop.cpp @@ -0,0 +1,67 @@ +#include "SimpleLoop.h" + +namespace havlak { + + SimpleLoop::SimpleLoop(shared_ptr bb, bool isReducible) { + _isReducible = isReducible; + _parent = nullptr; + _isRoot = false; + _nestingLevel = 0; + _depthLevel = 0; + if (bb != nullptr) { + _basicBlocks.insert(bb); + } + _header = bb; + } + + void SimpleLoop::addNode(shared_ptr bb) { + _basicBlocks.insert(bb); + } + + void SimpleLoop::addChildLoop(shared_ptr loop) { + _children.insert(loop); + } + + // Getters/Setters + set> SimpleLoop::getChildren() { + return _children; + } + + shared_ptr SimpleLoop::getParent() { + return _parent; + } + + int SimpleLoop::getNestingLevel() const { + return _nestingLevel; + } + + bool SimpleLoop::isRoot() const { + return _isRoot; + } + + void SimpleLoop::setParent(shared_ptr parent) { + _parent = parent; + if (parent != nullptr) { + parent->addChildLoop(shared_from_this()); + } + } + + void SimpleLoop::setIsRoot() { + _isRoot = true; + } + + void SimpleLoop::setCounter(int value) { + _counter = value; + } + + void SimpleLoop::setNestingLevel(int level) { + _nestingLevel = level; + if (level == 0) { + setIsRoot(); + } + } + + void SimpleLoop::setDepthLevel(int level) { + _depthLevel = level; + } +} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/SimpleLoop.h b/benchmarks/C++/src/havlak/SimpleLoop.h new file mode 100644 index 00000000..e828c5b1 --- /dev/null +++ b/benchmarks/C++/src/havlak/SimpleLoop.h @@ -0,0 +1,39 @@ +#ifndef SIMPLELOOP +#define SIMPLELOOP + +#include +#include "BasicBlock.h" + +using namespace std; + +namespace havlak { + class SimpleLoop : public enable_shared_from_this { + private: + set> _basicBlocks; + set> _children; + shared_ptr _parent; + shared_ptr _header; + bool _isReducible; + bool _isRoot; + int _nestingLevel; + int _counter; + int _depthLevel; + + public: + SimpleLoop(shared_ptr bb, bool isReducible); + + void addNode(shared_ptr bb); + void addChildLoop(shared_ptr loop); + set> getChildren(); + shared_ptr getParent(); + int getNestingLevel() const; + bool isRoot() const; + void setParent(shared_ptr parent); + void setIsRoot(); + void setCounter(int value); + void setNestingLevel(int level); + void setDepthLevel(int level); + }; +} + +#endif //SIMPLELOOP \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/UnionFindNode.cpp b/benchmarks/C++/src/havlak/UnionFindNode.cpp new file mode 100644 index 00000000..edf1c1ce --- /dev/null +++ b/benchmarks/C++/src/havlak/UnionFindNode.cpp @@ -0,0 +1,56 @@ +#include "UnionFindNode.h" + +namespace havlak { + + UnionFindNode::UnionFindNode() { } + + // Initialize this node. + void UnionFindNode::initNode(shared_ptr bb, int dfsNumber) { + _parent = shared_from_this(); + _bb = bb; + _dfsNumber = dfsNumber; + _loop = nullptr; + } + + // Union/Find Algorithm - The find routine. + shared_ptr UnionFindNode::findSet() { + Vector> nodeList = Vector>(); + + shared_ptr node = shared_from_this(); + while (node != node->_parent) { + if (node->_parent != node->_parent->_parent) { + nodeList.append(node); + } + node = node->_parent; + } + + // Path Compression, all nodes' parents point to the 1st level parent. + nodeList.forEach([&](shared_ptr iter) -> void { + iter->unionSet(_parent); + }); + return node; + } + + // Union/Find Algorithm - The union routine. + // Trivial. Assigning parent pointer is enough, we rely on path compression. + void UnionFindNode::unionSet(shared_ptr basicBlock) { + _parent = basicBlock; + } + + // Getters/Setters + shared_ptr UnionFindNode::getBb() { + return _bb; + } + + shared_ptr UnionFindNode::getLoop() { + return _loop; + } + + int UnionFindNode::getDfsNumber() { + return _dfsNumber; + } + + void UnionFindNode::setLoop(shared_ptr loop) { + _loop = loop; + } +} diff --git a/benchmarks/C++/src/havlak/UnionFindNode.h b/benchmarks/C++/src/havlak/UnionFindNode.h new file mode 100644 index 00000000..b83e1cce --- /dev/null +++ b/benchmarks/C++/src/havlak/UnionFindNode.h @@ -0,0 +1,33 @@ +#ifndef UNIONFINDNODE +#define UNIONFINDNODE + +#include +#include "SimpleLoop.h" +#include +#include + +using namespace std; + +namespace havlak { + class UnionFindNode : public enable_shared_from_this { + private: + shared_ptr _parent; + shared_ptr _bb; + shared_ptr _loop; + int _dfsNumber; + + public: + UnionFindNode(); + + void initNode(shared_ptr bb, int dfsNumber); + shared_ptr findSet(); + void unionSet(shared_ptr basicBlock); + shared_ptr getBb(); + shared_ptr getLoop(); + int getDfsNumber(); + void setLoop(shared_ptr loop); + }; +} + +#endif //UNIONFINDNODE + From 9ae5dbc04e63dbab40bac9681332f48c72db2d64 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 9 Jan 2024 18:22:12 +0000 Subject: [PATCH 19/40] [C++] Modernize Havlak and make it compile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - make int types consistent to avoid random conversion - add memory management, sanatized version works, but normal version segfaults (there’s a missing initialization fix for dictionary.h in some later commit) Signed-off-by: Stefan Marr --- benchmarks/C++/src/Havlak.cpp | 34 - benchmarks/C++/src/Havlak.h | 21 - benchmarks/C++/src/havlak.h | 586 ++++++++++++++++++ benchmarks/C++/src/havlak/BasicBlock.cpp | 34 - benchmarks/C++/src/havlak/BasicBlock.h | 29 - benchmarks/C++/src/havlak/BasicBlockEdge.cpp | 16 - benchmarks/C++/src/havlak/BasicBlockEdge.h | 21 - .../C++/src/havlak/ControlFlowGraph.cpp | 44 -- benchmarks/C++/src/havlak/ControlFlowGraph.h | 28 - .../C++/src/havlak/HavlakLoopFinder.cpp | 184 ------ benchmarks/C++/src/havlak/HavlakLoopFinder.h | 65 -- .../C++/src/havlak/LoopStructureGraph.cpp | 54 -- .../C++/src/havlak/LoopStructureGraph.h | 28 - benchmarks/C++/src/havlak/LoopTesterApp.cpp | 103 --- benchmarks/C++/src/havlak/LoopTesterApp.h | 31 - benchmarks/C++/src/havlak/SimpleLoop.cpp | 67 -- benchmarks/C++/src/havlak/SimpleLoop.h | 39 -- benchmarks/C++/src/havlak/UnionFindNode.cpp | 56 -- benchmarks/C++/src/havlak/UnionFindNode.h | 33 - benchmarks/C++/src/run.h | 4 + 20 files changed, 590 insertions(+), 887 deletions(-) delete mode 100644 benchmarks/C++/src/Havlak.cpp delete mode 100644 benchmarks/C++/src/Havlak.h create mode 100644 benchmarks/C++/src/havlak.h delete mode 100644 benchmarks/C++/src/havlak/BasicBlock.cpp delete mode 100644 benchmarks/C++/src/havlak/BasicBlock.h delete mode 100644 benchmarks/C++/src/havlak/BasicBlockEdge.cpp delete mode 100644 benchmarks/C++/src/havlak/BasicBlockEdge.h delete mode 100644 benchmarks/C++/src/havlak/ControlFlowGraph.cpp delete mode 100644 benchmarks/C++/src/havlak/ControlFlowGraph.h delete mode 100644 benchmarks/C++/src/havlak/HavlakLoopFinder.cpp delete mode 100644 benchmarks/C++/src/havlak/HavlakLoopFinder.h delete mode 100644 benchmarks/C++/src/havlak/LoopStructureGraph.cpp delete mode 100644 benchmarks/C++/src/havlak/LoopStructureGraph.h delete mode 100644 benchmarks/C++/src/havlak/LoopTesterApp.cpp delete mode 100644 benchmarks/C++/src/havlak/LoopTesterApp.h delete mode 100644 benchmarks/C++/src/havlak/SimpleLoop.cpp delete mode 100644 benchmarks/C++/src/havlak/SimpleLoop.h delete mode 100644 benchmarks/C++/src/havlak/UnionFindNode.cpp delete mode 100644 benchmarks/C++/src/havlak/UnionFindNode.h diff --git a/benchmarks/C++/src/Havlak.cpp b/benchmarks/C++/src/Havlak.cpp deleted file mode 100644 index c7d003ff..00000000 --- a/benchmarks/C++/src/Havlak.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "Havlak.h" - -namespace havlak { - bool Havlak::innerBenchmarkLoop(int innerIterations) { - bool result = verifyResult((make_shared())->main( - innerIterations, 50, 10 /* was 100 */, 10, 5), innerIterations); - return result; - } - - bool Havlak::verifyResult(any result, int innerIterations) { - vector r = any_cast>(result); - if (innerIterations == 15000) { return r[0] == 46602 && r[1] == 5213; } - if (innerIterations == 1500) { return r[0] == 6102 && r[1] == 5213; } - if (innerIterations == 150) { return r[0] == 2052 && r[1] == 5213; } - if (innerIterations == 15) { return r[0] == 1647 && r[1] == 5213; } - if (innerIterations == 1) { return r[0] == 1605 && r[1] == 5213; } - - - cout << "No verification result for " << innerIterations << " found" << endl; - cout << "Result is: " << r[0] << ", " << r[1] << endl; - - return false; - } - - any Havlak::benchmark() { - throw Error("Should never be reached"); - } - - - bool Havlak::verifyResult(any result) { - (void)result; - throw Error("Should never be reached"); - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/Havlak.h b/benchmarks/C++/src/Havlak.h deleted file mode 100644 index c8be3718..00000000 --- a/benchmarks/C++/src/Havlak.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef HAVLAK -#define HAVLAK - -#include "havlak/LoopTesterApp.h" -#include "Benchmark.h" -#include "som/Error.cpp" - -using namespace std; - -namespace havlak { - class Havlak : public Benchmark { - - public: - bool innerBenchmarkLoop(int innerIterations) override; - bool verifyResult(any result, int innerIterations); - any benchmark() override; - bool verifyResult(any result) override; - }; -} - -#endif //HAVLAK \ No newline at end of file diff --git a/benchmarks/C++/src/havlak.h b/benchmarks/C++/src/havlak.h new file mode 100644 index 00000000..014b17ff --- /dev/null +++ b/benchmarks/C++/src/havlak.h @@ -0,0 +1,586 @@ +#pragma once + +#include +#include + +#include "som/error.h" +#include "som/identity_set.h" + +using std::cout; +using std::endl; + +class BasicBlock : public CustomHash { + private: + Vector _inEdges{2}; + Vector _outEdges{2}; + int32_t _name; + + public: + explicit BasicBlock(int32_t name) : _name(name) {} + Vector* getInEdges() { return &_inEdges; } + Vector* getOutEdges() { return &_outEdges; } + int32_t getNumPred() { return static_cast(_inEdges.size()); } + void addOutEdge(BasicBlock* to) { _outEdges.append(to); } + void addInEdge(BasicBlock* from) { _inEdges.append(from); } + [[nodiscard]] int32_t customHash() const override { return _name; } + + bool equal(BasicBlock* other) const { return _name == other->_name; } +}; + +class BasicBlockEdge; + +class ControlFlowGraph { + private: + Vector _basicBlockMap{}; + BasicBlock* _startNode{nullptr}; + Vector _edgeList{}; + + public: + ControlFlowGraph() = default; + + ~ControlFlowGraph() { + _basicBlockMap.destroyValues(); + _edgeList.destroyValues(); + } + + BasicBlock* createNode(int32_t name) { + BasicBlock* node = nullptr; + if (_basicBlockMap.at(name) != nullptr) { + node = *_basicBlockMap.at(name); + } else { + node = new BasicBlock(name); + _basicBlockMap.atPut(name, node); + } + + if (getNumNodes() == 1) { + _startNode = node; + } + return node; + } + + void addEdge(BasicBlockEdge* edge) { _edgeList.append(edge); } + int32_t getNumNodes() { return static_cast(_basicBlockMap.size()); } + BasicBlock* getStartBasicBlock() { return _startNode; } + Vector* getBasicBlocks() { return &_basicBlockMap; } +}; + +class BasicBlockEdge { + private: + BasicBlock* _from; + BasicBlock* _to; + + public: + BasicBlockEdge(ControlFlowGraph& cfg, int32_t fromName, int32_t toName) + : _from(cfg.createNode(fromName)), _to(cfg.createNode(toName)) { + _from->addOutEdge(_to); + _to->addInEdge(_from); + } +}; + +class SimpleLoop { + private: + IdentitySet _basicBlocks{}; + IdentitySet _children{}; + SimpleLoop* _parent{nullptr}; + BasicBlock* _header; + bool _isReducible; + bool _isRoot{false}; + int32_t _nestingLevel{0}; + int32_t _counter{0}; + int32_t _depthLevel{0}; + + public: + SimpleLoop(BasicBlock* bb, bool isReducible) + : _header(bb), _isReducible(isReducible) { + if (bb != nullptr) { + _basicBlocks.add(bb); + } + } + + bool equal(SimpleLoop* other) const { return this == other; } + + void addNode(BasicBlock* bb) { _basicBlocks.add(bb); } + void addChildLoop(SimpleLoop* loop) { _children.add(loop); } + [[nodiscard]] IdentitySet* getChildren() { return &_children; } + [[nodiscard]] SimpleLoop* getParent() { return _parent; } + [[nodiscard]] int32_t getNestingLevel() const { return _nestingLevel; } + [[nodiscard]] bool isRoot() const { return _isRoot; } + + void setParent(SimpleLoop* parent) { + _parent = parent; + if (parent != nullptr) { + parent->addChildLoop(this); + } + } + + void setIsRoot() { _isRoot = true; } + void setCounter(int32_t value) { _counter = value; } + + void setNestingLevel(int32_t level) { + _nestingLevel = level; + if (level == 0) { + setIsRoot(); + } + } + + void setDepthLevel(int32_t level) { _depthLevel = level; } +}; + +class LoopStructureGraph { + private: + SimpleLoop* _root; + Vector _loops{}; + int32_t _loopCounter{0}; + + public: + LoopStructureGraph() : _root(new SimpleLoop(nullptr, true)) { + _root->setNestingLevel(0); + _root->setCounter(_loopCounter); + _loopCounter += 1; + _loops.append(_root); + } + + ~LoopStructureGraph() { _loops.destroyValues(); } + + [[nodiscard]] SimpleLoop* createNewLoop(BasicBlock* bb, bool isReducible) { + auto* loop = new SimpleLoop(bb, isReducible); + loop->setCounter(_loopCounter); + _loopCounter += 1; + _loops.append(loop); + return loop; + } + + void calculateNestingLevel() { + // link up all 1st level loops to artificial root node. + _loops.forEach([this](SimpleLoop* const& liter) -> void { + if (!liter->isRoot()) { + if (liter->getParent() == nullptr) { + liter->setParent(_root); + } + } + }); + + // recursively traverse the tree and assign levels. + calculateNestingLevelRec(_root, 0); + } + + void calculateNestingLevelRec(SimpleLoop* loop, int32_t depth) { + loop->setDepthLevel(depth); + loop->getChildren()->forEach( + [this, loop, depth](SimpleLoop* const& liter) -> void { + calculateNestingLevelRec(liter, depth + 1); + + loop->setNestingLevel( + std::max(loop->getNestingLevel(), 1 + liter->getNestingLevel())); + }); + } + + int32_t getNumLoops() { return static_cast(_loops.size()); } +}; + +class UnionFindNode { + private: + UnionFindNode* _parent; + BasicBlock* _bb; + SimpleLoop* _loop; + int32_t _dfsNumber; + + public: + UnionFindNode() = default; + + void initNode(BasicBlock* bb, int32_t dfsNumber) { + _parent = this; + _bb = bb; + _dfsNumber = dfsNumber; + _loop = nullptr; + } + + UnionFindNode* findSet() { + Vector nodeList{}; + + UnionFindNode* node = this; + while (node != node->_parent) { + if (node->_parent != node->_parent->_parent) { + nodeList.append(node); + } + node = node->_parent; + } + + // Path Compression, all nodes' parents point to the 1st level parent. + nodeList.forEach( + [&](UnionFindNode* const& iter) -> void { iter->unionSet(_parent); }); + return node; + } + + void unionSet(UnionFindNode* basicBlock) { _parent = basicBlock; } + [[nodiscard]] BasicBlock* getBb() const { return _bb; } + [[nodiscard]] SimpleLoop* getLoop() const { return _loop; } + [[nodiscard]] int32_t getDfsNumber() const { return _dfsNumber; } + void setLoop(SimpleLoop* loop) { _loop = loop; } +}; + +class HavlakLoopFinder { + private: + enum BasicBlockClass { + BB_TOP, // uninitialized + BB_NONHEADER, // a regular BB + BB_REDUCIBLE, // reducible loop + BB_SELF, // single BB loop + BB_IRREDUCIBLE, // irreducible loop + BB_DEAD, // a dead BB + BB_LAST // Sentinel + }; + + ControlFlowGraph& _cfg; // Control Flow Graph + LoopStructureGraph& _lsg; // Loop Structure Graph + + static constexpr int32_t UNVISITED = std::numeric_limits::max(); + static constexpr int32_t MAXNONBACKPREDS = static_cast(32 * 1024); + + Vector*> _nonBackPreds{}; + Vector*> _backPreds{}; + IdentityDictionary _number{}; + + int32_t _maxSize{0}; + int32_t* _header{nullptr}; + BasicBlockClass* _type{nullptr}; + int32_t* _last{nullptr}; + UnionFindNode** _nodes{nullptr}; + + public: + HavlakLoopFinder(ControlFlowGraph& cfg, LoopStructureGraph& lsg) + : _cfg(cfg), _lsg(lsg) {} + + ~HavlakLoopFinder() { + _nonBackPreds.destroyValues(); + _backPreds.destroyValues(); + delete[] _header; + delete[] _type; + delete[] _last; + + for (int32_t i = 0; i < _maxSize; i += 1) { + delete _nodes[i]; + } + delete[] _nodes; + } + + void findLoops() { + if (_cfg.getStartBasicBlock() == nullptr) { + return; + } + + const int32_t size = _cfg.getNumNodes(); + + _nonBackPreds.removeAll(); + _backPreds.removeAll(); + _number.removeAll(); + if (size > _maxSize) { + _header = new int32_t[size]; + _type = new BasicBlockClass[size]; + _last = new int32_t[size]; + _nodes = new UnionFindNode*[size]; + _maxSize = size; + } + + for (int32_t i = 0; i < size; i += 1) { + _nonBackPreds.append(new Set()); + _backPreds.append(new Vector()); + _nodes[i] = new UnionFindNode(); + } + + initAllNodes(); + identifyEdges(size); + + // Start node is root of all other loops. + _header[0] = 0; + for (int32_t w = size - 1; w >= 0; w--) { + // this is 'P' in Havlak's paper + Vector nodePool{}; + + BasicBlock* nodeW = _nodes[w]->getBb(); + if (nodeW != nullptr) { + stepD(w, nodePool); + + // Copy nodePool to workList. + Vector workList{}; + nodePool.forEach([&workList](UnionFindNode* const& niter) -> void { + workList.append(niter); + }); + + if (nodePool.size() != 0) { + _type[w] = BB_REDUCIBLE; + } + + // work the list... + // + while (!workList.isEmpty()) { + UnionFindNode* x = workList.removeFirst(); + + const auto nonBackSize = static_cast( + (*_nonBackPreds.at(x->getDfsNumber()))->size()); + if (nonBackSize > MAXNONBACKPREDS) { + return; + } + stepEProcessNonBackPreds(w, nodePool, workList, x); + } + + if ((nodePool.size() > 0) || (_type[w] == BB_SELF)) { + SimpleLoop* loop = + _lsg.createNewLoop(nodeW, _type[w] != BB_IRREDUCIBLE); + setLoopAttributes(w, nodePool, loop); + } + } + } // Step c + } // findLoops + + private: + bool isAncestor(int32_t w, int32_t v) { return w <= v && v <= _last[w]; } + + int32_t doDFS(BasicBlock* currentNode, int32_t current) { + _nodes[current]->initNode(currentNode, current); + _number.atPut(currentNode, current); + + int32_t lastId = current; + Vector* outerBlocks = currentNode->getOutEdges(); + + for (int32_t i = 0; i < static_cast(outerBlocks->size()); i += 1) { + BasicBlock* target = *outerBlocks->at(i); + if (*_number.at(target) == UNVISITED) { + lastId = doDFS(target, lastId + 1); + } + } + + _last[current] = lastId; + return lastId; + } + + void initAllNodes() { + _cfg.getBasicBlocks()->forEach([this](BasicBlock* const& bb) -> void { + _number.atPut(bb, UNVISITED); + }); + doDFS(_cfg.getStartBasicBlock(), 0); + } + + void identifyEdges(int32_t size) { + for (int32_t w = 0; w < size; w += 1) { + _header[w] = 0; + _type[w] = BB_NONHEADER; + + BasicBlock* nodeW = _nodes[w]->getBb(); + if (nodeW == nullptr) { + _type[w] = BB_DEAD; + } else { + processEdges(nodeW, w); + } + } + } + + void processEdges(BasicBlock* nodeW, int32_t w) { + if (nodeW->getNumPred() > 0) { + nodeW->getInEdges()->forEach([this, w](BasicBlock* const& nodeV) -> void { + const int32_t v = *_number.at(nodeV); + if (v != UNVISITED) { + if (isAncestor(w, v)) { + (*_backPreds.at(w))->append(v); + } else { + (*_nonBackPreds.at(w))->add(v); + } + } + }); + } + } + + void stepEProcessNonBackPreds(int32_t w, + Vector& nodePool, + Vector& workList, + UnionFindNode* x) { + (*_nonBackPreds.at(x->getDfsNumber())) + ->forEach([this, w, &nodePool, &workList](int32_t const& iter) -> void { + UnionFindNode* y = _nodes[iter]; + UnionFindNode* ydash = y->findSet(); + + if (!isAncestor(w, ydash->getDfsNumber())) { + _type[w] = BB_IRREDUCIBLE; + (*_nonBackPreds.at(w))->add(ydash->getDfsNumber()); + } else { + if (ydash->getDfsNumber() != w) { + if (!nodePool.hasSome([ydash](UnionFindNode* const& e) -> bool { + return e == ydash; + })) { + workList.append(ydash); + nodePool.append(ydash); + } + } + } + }); + } + + void setLoopAttributes(int32_t w, + Vector& nodePool, + SimpleLoop* loop) { + _nodes[w]->setLoop(loop); + + nodePool.forEach([this, w, loop](UnionFindNode* const& node) -> void { + _header[node->getDfsNumber()] = w; + node->unionSet(_nodes[w]); + + // Nested loops are not added, but linked together. + if (node->getLoop() != nullptr) { + node->getLoop()->setParent(loop); + } else { + loop->addNode(node->getBb()); + } + }); + } + + void stepD(int32_t w, Vector& nodePool) { + (*_backPreds.at(w)) + ->forEach([this, w, &nodePool](int32_t const& v) -> void { + if (v != w) { + nodePool.append(_nodes[v]->findSet()); + } else { + _type[w] = BB_SELF; + } + }); + } +}; + +class LoopTesterApp { + private: + ControlFlowGraph _cfg{}; + LoopStructureGraph _lsg{}; + + int32_t buildDiamond(int32_t start) { + const int32_t bb0 = start; + _cfg.addEdge(new BasicBlockEdge(_cfg, bb0, bb0 + 1)); + _cfg.addEdge(new BasicBlockEdge(_cfg, bb0, bb0 + 2)); + _cfg.addEdge(new BasicBlockEdge(_cfg, bb0 + 1, bb0 + 3)); + _cfg.addEdge(new BasicBlockEdge(_cfg, bb0 + 2, bb0 + 3)); + + return bb0 + 3; + } + + void buildConnect(int32_t start, int32_t end) { + _cfg.addEdge(new BasicBlockEdge(_cfg, start, end)); + } + + int32_t buildStraight(int32_t start, int32_t n) { + for (int32_t i = 0; i < n; i += 1) { + buildConnect(start + i, start + i + 1); + } + return start + n; + } + + int32_t buildBaseLoop(int32_t from) { + const int32_t header = buildStraight(from, 1); + const int32_t diamond1 = buildDiamond(header); + const int32_t d11 = buildStraight(diamond1, 1); + const int32_t diamond2 = buildDiamond(d11); + int32_t footer = buildStraight(diamond2, 1); + buildConnect(diamond2, d11); + buildConnect(diamond1, header); + buildConnect(footer, from); + footer = buildStraight(footer, 1); + return footer; + } + + void constructSimpleCFG() { + _cfg.createNode(0); + buildBaseLoop(0); + _cfg.createNode(1); + + _cfg.addEdge(new BasicBlockEdge(_cfg, 0, 2)); + } + + public: + LoopTesterApp() { _cfg.createNode(0); } + + std::array main(int32_t numDummyLoops, + int32_t findLoopIterations, + int32_t parLoops, + int32_t pparLoops, + int32_t ppparLoops) { + constructSimpleCFG(); + addDummyLoops(numDummyLoops); + constructCFG(parLoops, pparLoops, ppparLoops); + findLoops(_lsg); + for (int32_t i = 0; i < findLoopIterations; i += 1) { + LoopStructureGraph l{}; + findLoops(l); + } + + _lsg.calculateNestingLevel(); + return {_lsg.getNumLoops(), _cfg.getNumNodes()}; + } + + void constructCFG(int32_t parLoops, int32_t pparLoops, int32_t ppparLoops) { + int32_t n = 2; + + for (int32_t parlooptrees = 0; parlooptrees < parLoops; parlooptrees += 1) { + _cfg.createNode(n + 1); + buildConnect(2, n + 1); + n += 1; + + for (int32_t i = 0; i < pparLoops; i += 1) { + const int32_t top = n; + n = buildStraight(n, 1); + for (int32_t j = 0; j < ppparLoops; j += 1) { + n = buildBaseLoop(n); + } + const int32_t bottom = buildStraight(n, 1); + buildConnect(n, top); + n = bottom; + } + buildConnect(n, 1); + } + } + + void addDummyLoops(int32_t numDummyLoops) { + for (int32_t dummyloop = 0; dummyloop < numDummyLoops; dummyloop += 1) { + findLoops(_lsg); + } + } + + void findLoops(LoopStructureGraph& loopStructure) { + HavlakLoopFinder finder(_cfg, loopStructure); + finder.findLoops(); + } +}; + +class Havlak : public Benchmark { + public: + bool inner_benchmark_loop(int32_t inner_iterations) override { + const bool result = verifyResult( + LoopTesterApp().main(inner_iterations, 50, 10 /* was 100 */, 10, 5), + inner_iterations); + return result; + } + + bool verifyResult(std::array r, int32_t innerIterations) { + if (innerIterations == 15000) { + return r[0] == 46602 && r[1] == 5213; + } + if (innerIterations == 1500) { + return r[0] == 6102 && r[1] == 5213; + } + if (innerIterations == 150) { + return r[0] == 2052 && r[1] == 5213; + } + if (innerIterations == 15) { + return r[0] == 1647 && r[1] == 5213; + } + if (innerIterations == 1) { + return r[0] == 1605 && r[1] == 5213; + } + + cout << "No verification result for " << innerIterations << " found" + << endl; + cout << "Result is: " << r[0] << ", " << r[1] << endl; + + return false; + } + + void* benchmark() override { throw Error("Should never be reached"); } + + bool verify_result(void*) override { throw Error("Should never be reached"); } +}; diff --git a/benchmarks/C++/src/havlak/BasicBlock.cpp b/benchmarks/C++/src/havlak/BasicBlock.cpp deleted file mode 100644 index f7e76322..00000000 --- a/benchmarks/C++/src/havlak/BasicBlock.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "BasicBlock.h" - -namespace havlak { - - BasicBlock::BasicBlock(int name) : CustomHash(){ - _name = name; - _inEdges = make_shared>>(2); - _outEdges = make_shared>>(2); - } - - shared_ptr>> BasicBlock::getInEdges() { - return _inEdges; - } - - shared_ptr>> BasicBlock::getOutEdges() { - return _outEdges; - } - - int BasicBlock::getNumPred() { - return _inEdges->size(); - } - - void BasicBlock::addOutEdge(shared_ptr to) { - _outEdges->append(to); - } - - void BasicBlock::addInEdge(shared_ptr from) { - _inEdges->append(from); - } - - int BasicBlock::customHash() { - return _name; - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/BasicBlock.h b/benchmarks/C++/src/havlak/BasicBlock.h deleted file mode 100644 index 69e14987..00000000 --- a/benchmarks/C++/src/havlak/BasicBlock.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef BASICBLOCK -#define BASICBLOCK - -#include "../som/Vector.cpp" -#include -#include "../som/Dictionary.cpp" -using namespace std; - -namespace havlak { - class BasicBlock: public CustomHash { - private: - shared_ptr>> _inEdges; - shared_ptr>> _outEdges; - int _name; - - public: - - BasicBlock(int name); - shared_ptr>> getInEdges(); - shared_ptr>> getOutEdges(); - int getNumPred(); - void addOutEdge(shared_ptr to); - void addInEdge(shared_ptr from); - int customHash() override; - - }; -} - -#endif //BASICBLOCK \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/BasicBlockEdge.cpp b/benchmarks/C++/src/havlak/BasicBlockEdge.cpp deleted file mode 100644 index 64eb8e15..00000000 --- a/benchmarks/C++/src/havlak/BasicBlockEdge.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "BasicBlock.h" -#include "ControlFlowGraph.h" - -using namespace std; - -namespace havlak { - - BasicBlockEdge::BasicBlockEdge(shared_ptr cfg, int fromName, int toName) { - _from = cfg->createNode(fromName); - _to = cfg->createNode(toName); - - _from->addOutEdge(_to); - _to->addInEdge(_from); - } - -} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/BasicBlockEdge.h b/benchmarks/C++/src/havlak/BasicBlockEdge.h deleted file mode 100644 index a5d47e93..00000000 --- a/benchmarks/C++/src/havlak/BasicBlockEdge.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef BASICBLOCKEDGE -#define BASICBLOCKEDGE - -#include "BasicBlock.h" - -using namespace std; - -namespace havlak { - class ControlFlowGraph; - - class BasicBlockEdge : public enable_shared_from_this { - private: - shared_ptr _from; - shared_ptr _to; - - public: - BasicBlockEdge(shared_ptr cfg, int fromName, int toName); - }; -} - -#endif //BASICBLOCKEDGE \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/ControlFlowGraph.cpp b/benchmarks/C++/src/havlak/ControlFlowGraph.cpp deleted file mode 100644 index be383035..00000000 --- a/benchmarks/C++/src/havlak/ControlFlowGraph.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "ControlFlowGraph.h" - -#include - -namespace havlak { - - ControlFlowGraph::ControlFlowGraph() { - _startNode = nullptr; - _basicBlockMap = make_shared>>(); - _edgeList = make_shared>>(); - } - - shared_ptr ControlFlowGraph::createNode(int name) { - shared_ptr node; - if (_basicBlockMap != nullptr && _basicBlockMap->atPtr(name) != nullptr) { - node = _basicBlockMap->atPtr(name); - } else { - node = make_shared(name); - _basicBlockMap->atPut(name, node); - } - - if (getNumNodes() == 1) { - _startNode = node; - } - return node; - } - - void ControlFlowGraph::addEdge(shared_ptr edge) { - _edgeList->append(edge); - } - - int ControlFlowGraph::getNumNodes() { - return _basicBlockMap->size(); - } - - shared_ptr ControlFlowGraph::getStartBasicBlock() { - return _startNode; - } - - shared_ptr>> ControlFlowGraph::getBasicBlocks() { - return _basicBlockMap; - } - -} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/ControlFlowGraph.h b/benchmarks/C++/src/havlak/ControlFlowGraph.h deleted file mode 100644 index a34d3632..00000000 --- a/benchmarks/C++/src/havlak/ControlFlowGraph.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef CONTROLFLOWGRAPH -#define CONTROLFLOWGRAPH - -#include "BasicBlock.h" -#include "BasicBlockEdge.h" -#include "../som/Vector.cpp" -using namespace std; - -namespace havlak { - - class ControlFlowGraph { - private: - shared_ptr>> _basicBlockMap; - shared_ptr _startNode; - shared_ptr>> _edgeList; - - public: - ControlFlowGraph(); - shared_ptr createNode(int name); - void addEdge(shared_ptr edge); - int getNumNodes(); - shared_ptr getStartBasicBlock(); - shared_ptr>> getBasicBlocks(); - - }; -} - -#endif //CONTROLFLOWGRAPH diff --git a/benchmarks/C++/src/havlak/HavlakLoopFinder.cpp b/benchmarks/C++/src/havlak/HavlakLoopFinder.cpp deleted file mode 100644 index b2ec8fd8..00000000 --- a/benchmarks/C++/src/havlak/HavlakLoopFinder.cpp +++ /dev/null @@ -1,184 +0,0 @@ - -#include "HavlakLoopFinder.h" - -namespace havlak { - - bool HavlakLoopFinder::isAncestor(int w, int v) { - return w <= v && v <= _last[w]; - } - - int HavlakLoopFinder::doDFS(shared_ptr currentNode, int current) { - _nodes[current]->initNode(currentNode, current); - _number->atPut(currentNode, current); - int lastId = current; - shared_ptr>> outerBlocks = currentNode->getOutEdges(); - for (int i = 0; i < outerBlocks->size(); i++) { - shared_ptr target = outerBlocks->at(i); - if (_number->at(target) == UNVISITED) { - lastId = doDFS(target, lastId + 1); - } - } - - _last[current] = lastId; - return lastId; - } - - void HavlakLoopFinder::initAllNodes() { - _cfg->getBasicBlocks()->forEach([&](shared_ptr bb) -> void { - _number->atPut(bb, UNVISITED); - }); - doDFS(_cfg->getStartBasicBlock(), 0); - } - - void HavlakLoopFinder::identifyEdges(int size) { - for (int w = 0; w < size; w++) { - _header[w] = 0; - _type[w] = BB_NONHEADER; - - shared_ptr nodeW = _nodes[w]->getBb(); - if (nodeW == nullptr) { - _type[w] = BB_DEAD; - } else { - processEdges(nodeW, w); - } - } - } - - void HavlakLoopFinder::processEdges(shared_ptr nodeW, int w) { - if (nodeW->getNumPred() > 0) { - nodeW->getInEdges()->forEach([&](shared_ptr nodeV) -> void { - int v = _number->at(nodeV); - if (v != UNVISITED) { - if (isAncestor(w, v)) { - _backPreds->at(w)->append(v); - } else { - _nonBackPreds->at(w).insert(v); - } - } - }); - } - } - - void HavlakLoopFinder::stepEProcessNonBackPreds(int w, shared_ptr>> nodePool, shared_ptr>> workList, shared_ptr x) { - for (int iter : _nonBackPreds->at(x->getDfsNumber())) { - shared_ptr y = _nodes[iter]; - shared_ptr ydash = y->findSet(); - - if (!isAncestor(w, ydash->getDfsNumber())) { - _type[w] = BB_IRREDUCIBLE; - _nonBackPreds->at(w).insert(ydash->getDfsNumber()); - } else { - if (ydash->getDfsNumber() != w) { - if (!nodePool->hasSome([&](shared_ptr e) -> bool { - return e == ydash; - })) { - workList->append(ydash); - nodePool->append(ydash); - } - } - } - } - } - - - void HavlakLoopFinder::setLoopAttributes(int w, shared_ptr>> nodePool, shared_ptr loop) { - _nodes[w]->setLoop(loop); - - nodePool->forEach([&](shared_ptr node) -> void { - _header[node->getDfsNumber()] = w; - node->unionSet(_nodes[w]); - - // Nested loops are not added, but linked together. - if (node->getLoop() != nullptr) { - node->getLoop()->setParent(loop); - } else { - loop->addNode(node->getBb()); - } - }); - } - - void HavlakLoopFinder::stepD(int w, shared_ptr>> nodePool) { - - _backPreds->at(w)->forEach([&](int v) -> void { - if (v != w) { - nodePool->append(_nodes[v]->findSet()); - } else { - _type[w] = BB_SELF; - } - }); - } - - - - HavlakLoopFinder::HavlakLoopFinder(shared_ptr cfg, shared_ptr lsg) { - _cfg = cfg; - _lsg = lsg; - } - - void HavlakLoopFinder::findLoops() { - if (_cfg->getStartBasicBlock() == nullptr) { - return; - } - - int size = _cfg->getNumNodes(); - - _nonBackPreds->removeAll(); - _backPreds->removeAll(); - _number->removeAll(); - if (size > _maxSize) { - _header = new int[size]; - _type = new BasicBlockClass[size]; - _last = new int[size]; - _nodes = new shared_ptr[size]; - _maxSize = size; - } - - for (int i = 0; i < size; ++i) { - _nodes[i] = make_shared(); - _backPreds->append(make_shared>()); - } - - initAllNodes(); - identifyEdges(size); - - // Start node is root of all other loops. - _header[0] = 0; - for (int w = size - 1; w >= 0; w--) { - // this is 'P' in Havlak's paper - shared_ptr>> nodePool = make_shared>>(); - - shared_ptr nodeW = _nodes[w]->getBb(); - if (nodeW != nullptr) { - stepD(w, nodePool); - - // Copy nodePool to workList. - // - shared_ptr>> workList = make_shared>>(); - nodePool->forEach([&](shared_ptr niter) -> void { - workList->append(niter); - }); - - if (nodePool->size() != 0) { - _type[w] = BB_REDUCIBLE; - } - - // work the list... - // - while (!workList->isEmpty()) { - shared_ptr x = workList->removeFirst(); - - int nonBackSize = _nonBackPreds->at(x->getDfsNumber()).size(); - if (nonBackSize > MAXNONBACKPREDS) { - return; - } - stepEProcessNonBackPreds(w, nodePool, workList, x); - } - - if ((nodePool->size() > 0) || (_type[w] == BB_SELF)) { - shared_ptr loop = _lsg->createNewLoop(nodeW, _type[w] != BB_IRREDUCIBLE); - setLoopAttributes(w, nodePool, loop); - } - } - } // Step c - } // findLoops -} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/HavlakLoopFinder.h b/benchmarks/C++/src/havlak/HavlakLoopFinder.h deleted file mode 100644 index cf1b2947..00000000 --- a/benchmarks/C++/src/havlak/HavlakLoopFinder.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef HAVLAKLOOPFINDER -#define HAVLAKLOOPFINDER - -#include "ControlFlowGraph.h" -#include "LoopStructureGraph.h" -#include "UnionFindNode.h" -#include -#include -#include -#include "../som/IdentityDictionary.cpp" - -using namespace std; - -namespace havlak { - class HavlakLoopFinder { - private: - - enum BasicBlockClass { - BB_TOP, // uninitialized - BB_NONHEADER, // a regular BB - BB_REDUCIBLE, // reducible loop - BB_SELF, // single BB loop - BB_IRREDUCIBLE, // irreducible loop - BB_DEAD, // a dead BB - BB_LAST // Sentinel - }; - - shared_ptr _cfg; // Control Flow Graph - shared_ptr _lsg; // Loop Structure Graph - - static constexpr int UNVISITED = numeric_limits::max(); - static constexpr int MAXNONBACKPREDS = 32 * 1024; - - shared_ptr>> _nonBackPreds = make_shared>>() ; - shared_ptr>>> _backPreds = make_shared>>>(); - shared_ptr> _number = make_shared>(); - - int _maxSize = 0; - int* _header; - BasicBlockClass* _type; - int* _last; - shared_ptr* _nodes; - - public: - HavlakLoopFinder(shared_ptr cfg, shared_ptr lsg); - void findLoops(); - - private: - bool isAncestor(int w, int v); - int doDFS(shared_ptr currentNode, int current); - void initAllNodes(); - void identifyEdges(int size); - void processEdges(shared_ptr nodeW, int w); - void stepEProcessNonBackPreds(int w, shared_ptr>> nodePool, shared_ptr>> workList, shared_ptr x); - - - void setLoopAttributes(int w, shared_ptr>> nodePool, shared_ptr loop); - void stepD(int w, shared_ptr>> nodePool); - - - - }; -} - -#endif //HAVLAKLOOPFINDER \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/LoopStructureGraph.cpp b/benchmarks/C++/src/havlak/LoopStructureGraph.cpp deleted file mode 100644 index 44009a54..00000000 --- a/benchmarks/C++/src/havlak/LoopStructureGraph.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "LoopStructureGraph.h" - -using namespace std; - -namespace havlak { - - - LoopStructureGraph::LoopStructureGraph() { - _loopCounter = 0; - _loops = make_shared>>(); - _root = make_shared(nullptr, true); - _root->setNestingLevel(0); - _root->setCounter(_loopCounter); - _loopCounter += 1; - _loops->append(_root); - } - - shared_ptr LoopStructureGraph::createNewLoop(shared_ptr bb, bool isReducible) { - shared_ptr loop = make_shared(bb, isReducible); - loop->setCounter(_loopCounter); - _loopCounter += 1; - _loops->append(loop); - return loop; - } - - void LoopStructureGraph::calculateNestingLevel() { - // link up all 1st level loops to artificial root node. - _loops->forEach([&](shared_ptr liter) -> void { - if (!liter->isRoot()) { - if (liter->getParent() == nullptr) { - liter->setParent(_root); - } - } - }); - - // recursively traverse the tree and assign levels. - calculateNestingLevelRec(_root, 0); - } - - void LoopStructureGraph::calculateNestingLevelRec(shared_ptr loop, int depth) { - loop->setDepthLevel(depth); - for (auto liter : loop->getChildren()) { - calculateNestingLevelRec(liter, depth + 1); - - loop->setNestingLevel(std::max(loop->getNestingLevel(), - 1 + liter->getNestingLevel())); - } - } - - int LoopStructureGraph::getNumLoops() { - return _loops->size(); - } - -} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/LoopStructureGraph.h b/benchmarks/C++/src/havlak/LoopStructureGraph.h deleted file mode 100644 index 9efce91d..00000000 --- a/benchmarks/C++/src/havlak/LoopStructureGraph.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef LOOPSTRUCTUREGRAPH -#define LOOPSTRUCTUREGRAPH - -#include -#include "SimpleLoop.h" -#include "../som/Vector.cpp" - -using namespace std; - -namespace havlak { - class LoopStructureGraph { - private: - shared_ptr _root; - shared_ptr>> _loops; - int _loopCounter; - - public: - - LoopStructureGraph(); - - shared_ptr createNewLoop(shared_ptr bb, bool isReducible); - void calculateNestingLevel(); - void calculateNestingLevelRec(shared_ptr loop, int depth); - int getNumLoops(); - }; -} - -#endif //LOOPSTRUCTUREGRAPH \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/LoopTesterApp.cpp b/benchmarks/C++/src/havlak/LoopTesterApp.cpp deleted file mode 100644 index 24502a35..00000000 --- a/benchmarks/C++/src/havlak/LoopTesterApp.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "LoopTesterApp.h" - -using namespace std; - -namespace havlak { - - int LoopTesterApp::buildDiamond(int start) { - int bb0 = start; - _cfg->addEdge(make_shared(_cfg, bb0, bb0 + 1)); - _cfg->addEdge(make_shared(_cfg, bb0, bb0 + 2)); - _cfg->addEdge(make_shared(_cfg, bb0 + 1, bb0 + 3)); - _cfg->addEdge(make_shared(_cfg, bb0 + 2, bb0 + 3)); - - return bb0 + 3; - } - - void LoopTesterApp::buildConnect(int start, int end) { - _cfg->addEdge(make_shared(_cfg, start, end)); - } - - int LoopTesterApp::buildStraight(int start, int n) { - for (int i = 0; i < n; i++) { - buildConnect(start + i, start + i + 1); - } - return start + n; - } - - int LoopTesterApp::buildBaseLoop(int from) { - int header = buildStraight(from, 1); - int diamond1 = buildDiamond(header); - int d11 = buildStraight(diamond1, 1); - int diamond2 = buildDiamond(d11); - int footer = buildStraight(diamond2, 1); - buildConnect(diamond2, d11); - buildConnect(diamond1, header); - buildConnect(footer, from); - footer = buildStraight(footer, 1); - return footer; - } - - void LoopTesterApp::constructSimpleCFG() { - _cfg->createNode(0); - buildBaseLoop(0); - _cfg->createNode(1); - - _cfg->addEdge(make_shared(_cfg, 0, 2)); - } - - LoopTesterApp::LoopTesterApp() { - _cfg = make_shared(); - _lsg = make_shared(); - _cfg->createNode(0); - - } - - vector LoopTesterApp::main(int numDummyLoops, int findLoopIterations, int parLoops, - int pparLoops, int ppparLoops) { - constructSimpleCFG(); - addDummyLoops(numDummyLoops); - constructCFG(parLoops, pparLoops, ppparLoops); - findLoops(_lsg); - for (int i = 0; i < findLoopIterations; i++) { - findLoops(make_shared()); - } - - _lsg->calculateNestingLevel(); - vector result = {_lsg->getNumLoops(), _cfg->getNumNodes()}; - return result; - } - - void LoopTesterApp::constructCFG(int parLoops, int pparLoops, int ppparLoops) { - int n = 2; - - for (int parlooptrees = 0; parlooptrees < parLoops; parlooptrees++) { - _cfg->createNode(n + 1); - buildConnect(2, n + 1); - n += 1; - - for (int i = 0; i < pparLoops; i++) { - int top = n; - n = buildStraight(n, 1); - for (int j = 0; j < ppparLoops; j++) { - n = buildBaseLoop(n); - } - int bottom = buildStraight(n, 1); - buildConnect(n, top); - n = bottom; - } - buildConnect(n, 1); - } - } - - void LoopTesterApp::addDummyLoops(int numDummyLoops) { - for (int dummyloop = 0; dummyloop < numDummyLoops; dummyloop++) { - findLoops(_lsg); - } - } - - void LoopTesterApp::findLoops(shared_ptr loopStructure) { - shared_ptr finder = make_shared(_cfg, loopStructure); - finder->findLoops(); - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/LoopTesterApp.h b/benchmarks/C++/src/havlak/LoopTesterApp.h deleted file mode 100644 index 95b1aeb4..00000000 --- a/benchmarks/C++/src/havlak/LoopTesterApp.h +++ /dev/null @@ -1,31 +0,0 @@ -#include "ControlFlowGraph.h" -#include "LoopStructureGraph.h" -#include "HavlakLoopFinder.h" -#include -#include - -using namespace std; - -namespace havlak { - class LoopTesterApp { - - private: - - shared_ptr _cfg; - shared_ptr _lsg; - - int buildDiamond(int start); - void buildConnect(int start, int end); - int buildStraight(int start, int n); - int buildBaseLoop(int from); - void constructSimpleCFG(); - - public: - LoopTesterApp(); - vector main(int numDummyLoops, int findLoopIterations, int parLoops, - int pparLoops, int ppparLoops); - void constructCFG(int parLoops, int pparLoops, int ppparLoops); - void addDummyLoops(int numDummyLoops); - void findLoops(shared_ptr loopStructure); - }; -} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/SimpleLoop.cpp b/benchmarks/C++/src/havlak/SimpleLoop.cpp deleted file mode 100644 index 3476dc3f..00000000 --- a/benchmarks/C++/src/havlak/SimpleLoop.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "SimpleLoop.h" - -namespace havlak { - - SimpleLoop::SimpleLoop(shared_ptr bb, bool isReducible) { - _isReducible = isReducible; - _parent = nullptr; - _isRoot = false; - _nestingLevel = 0; - _depthLevel = 0; - if (bb != nullptr) { - _basicBlocks.insert(bb); - } - _header = bb; - } - - void SimpleLoop::addNode(shared_ptr bb) { - _basicBlocks.insert(bb); - } - - void SimpleLoop::addChildLoop(shared_ptr loop) { - _children.insert(loop); - } - - // Getters/Setters - set> SimpleLoop::getChildren() { - return _children; - } - - shared_ptr SimpleLoop::getParent() { - return _parent; - } - - int SimpleLoop::getNestingLevel() const { - return _nestingLevel; - } - - bool SimpleLoop::isRoot() const { - return _isRoot; - } - - void SimpleLoop::setParent(shared_ptr parent) { - _parent = parent; - if (parent != nullptr) { - parent->addChildLoop(shared_from_this()); - } - } - - void SimpleLoop::setIsRoot() { - _isRoot = true; - } - - void SimpleLoop::setCounter(int value) { - _counter = value; - } - - void SimpleLoop::setNestingLevel(int level) { - _nestingLevel = level; - if (level == 0) { - setIsRoot(); - } - } - - void SimpleLoop::setDepthLevel(int level) { - _depthLevel = level; - } -} \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/SimpleLoop.h b/benchmarks/C++/src/havlak/SimpleLoop.h deleted file mode 100644 index e828c5b1..00000000 --- a/benchmarks/C++/src/havlak/SimpleLoop.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef SIMPLELOOP -#define SIMPLELOOP - -#include -#include "BasicBlock.h" - -using namespace std; - -namespace havlak { - class SimpleLoop : public enable_shared_from_this { - private: - set> _basicBlocks; - set> _children; - shared_ptr _parent; - shared_ptr _header; - bool _isReducible; - bool _isRoot; - int _nestingLevel; - int _counter; - int _depthLevel; - - public: - SimpleLoop(shared_ptr bb, bool isReducible); - - void addNode(shared_ptr bb); - void addChildLoop(shared_ptr loop); - set> getChildren(); - shared_ptr getParent(); - int getNestingLevel() const; - bool isRoot() const; - void setParent(shared_ptr parent); - void setIsRoot(); - void setCounter(int value); - void setNestingLevel(int level); - void setDepthLevel(int level); - }; -} - -#endif //SIMPLELOOP \ No newline at end of file diff --git a/benchmarks/C++/src/havlak/UnionFindNode.cpp b/benchmarks/C++/src/havlak/UnionFindNode.cpp deleted file mode 100644 index edf1c1ce..00000000 --- a/benchmarks/C++/src/havlak/UnionFindNode.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "UnionFindNode.h" - -namespace havlak { - - UnionFindNode::UnionFindNode() { } - - // Initialize this node. - void UnionFindNode::initNode(shared_ptr bb, int dfsNumber) { - _parent = shared_from_this(); - _bb = bb; - _dfsNumber = dfsNumber; - _loop = nullptr; - } - - // Union/Find Algorithm - The find routine. - shared_ptr UnionFindNode::findSet() { - Vector> nodeList = Vector>(); - - shared_ptr node = shared_from_this(); - while (node != node->_parent) { - if (node->_parent != node->_parent->_parent) { - nodeList.append(node); - } - node = node->_parent; - } - - // Path Compression, all nodes' parents point to the 1st level parent. - nodeList.forEach([&](shared_ptr iter) -> void { - iter->unionSet(_parent); - }); - return node; - } - - // Union/Find Algorithm - The union routine. - // Trivial. Assigning parent pointer is enough, we rely on path compression. - void UnionFindNode::unionSet(shared_ptr basicBlock) { - _parent = basicBlock; - } - - // Getters/Setters - shared_ptr UnionFindNode::getBb() { - return _bb; - } - - shared_ptr UnionFindNode::getLoop() { - return _loop; - } - - int UnionFindNode::getDfsNumber() { - return _dfsNumber; - } - - void UnionFindNode::setLoop(shared_ptr loop) { - _loop = loop; - } -} diff --git a/benchmarks/C++/src/havlak/UnionFindNode.h b/benchmarks/C++/src/havlak/UnionFindNode.h deleted file mode 100644 index b83e1cce..00000000 --- a/benchmarks/C++/src/havlak/UnionFindNode.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef UNIONFINDNODE -#define UNIONFINDNODE - -#include -#include "SimpleLoop.h" -#include -#include - -using namespace std; - -namespace havlak { - class UnionFindNode : public enable_shared_from_this { - private: - shared_ptr _parent; - shared_ptr _bb; - shared_ptr _loop; - int _dfsNumber; - - public: - UnionFindNode(); - - void initNode(shared_ptr bb, int dfsNumber); - shared_ptr findSet(); - void unionSet(shared_ptr basicBlock); - shared_ptr getBb(); - shared_ptr getLoop(); - int getDfsNumber(); - void setLoop(shared_ptr loop); - }; -} - -#endif //UNIONFINDNODE - diff --git a/benchmarks/C++/src/run.h b/benchmarks/C++/src/run.h index 968da0fe..1da01a32 100644 --- a/benchmarks/C++/src/run.h +++ b/benchmarks/C++/src/run.h @@ -6,6 +6,7 @@ #include "bounce.h" #include "cd.h" #include "deltablue.h" +#include "havlak.h" #include "json.h" #include "list.h" #include "mandelbrot.h" @@ -60,6 +61,9 @@ class Run { if (name == "CD") { return []() -> Benchmark* { return new CD(); }; } + if (name == "Havlak") { + return []() -> Benchmark* { return new Havlak(); }; + } if (name == "Json") { return []() -> Benchmark* { return new Json(); }; } From 469565921510397fbac445a06f1fb3ef1301da7c Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 10 Jan 2024 14:50:01 +0000 Subject: [PATCH 20/40] [C++] Prefer += 1 over ++, same for -= 1 Signed-off-by: Stefan Marr --- benchmarks/C++/src/bounce.h | 4 ++-- benchmarks/C++/src/cd.h | 6 +++--- benchmarks/C++/src/deltablue.h | 8 ++++---- benchmarks/C++/src/havlak.h | 2 +- benchmarks/C++/src/permute.h | 4 ++-- benchmarks/C++/src/queens.h | 4 ++-- benchmarks/C++/src/richards.h | 4 ++-- benchmarks/C++/src/run.h | 2 +- benchmarks/C++/src/sieve.h | 4 ++-- benchmarks/C++/src/som/dictionary.h | 10 +++++----- benchmarks/C++/src/som/vector.h | 20 ++++++++++---------- benchmarks/C++/src/storage.h | 4 ++-- benchmarks/C++/src/towers.h | 4 ++-- 13 files changed, 38 insertions(+), 38 deletions(-) diff --git a/benchmarks/C++/src/bounce.h b/benchmarks/C++/src/bounce.h index 98c4b3f3..1e3c8dcc 100644 --- a/benchmarks/C++/src/bounce.h +++ b/benchmarks/C++/src/bounce.h @@ -70,10 +70,10 @@ class Bounce : public Benchmark { ball = Ball(random); } - for (int32_t j = 0; j < 50; j++) { + for (int32_t j = 0; j < 50; j += 1) { for (auto& ball : balls) { if (ball.bounce()) { - bounces++; + bounces += 1; } } } diff --git a/benchmarks/C++/src/cd.h b/benchmarks/C++/src/cd.h index 1fe3df67..a69aea1a 100644 --- a/benchmarks/C++/src/cd.h +++ b/benchmarks/C++/src/cd.h @@ -843,9 +843,9 @@ class CollisionDetector { allReduced->forEach( [collisions](const Vector* const& reduced) -> void { - for (size_t i = 0; i < reduced->size(); ++i) { + for (size_t i = 0; i < reduced->size(); i += 1) { const Motion* motion1 = reduced->at(i); - for (size_t j = i + 1; j < reduced->size(); ++j) { + for (size_t j = i + 1; j < reduced->size(); j += 1) { const Motion* motion2 = reduced->at(j); std::optional collision = motion1->findIntersection(*motion2); @@ -897,7 +897,7 @@ class CD : public Benchmark { CollisionDetector detector{}; size_t actualCollisions = 0; - for (int32_t i = 0; i < numFrames; i++) { + for (int32_t i = 0; i < numFrames; i += 1) { const double time = i / 10.0; Vector frame = simulator.simulate(time); Vector* collisions = detector.handleNewFrame(frame); diff --git a/benchmarks/C++/src/deltablue.h b/benchmarks/C++/src/deltablue.h index c1638b50..21b3b456 100644 --- a/benchmarks/C++/src/deltablue.h +++ b/benchmarks/C++/src/deltablue.h @@ -643,7 +643,7 @@ class Planner { Plan* plan = planner.extractPlanFromConstraints(editV); delete editV; - for (int i = 0; i < 100; i++) { + for (int32_t i = 0; i < 100; i += 1) { vars[0]->setValue(i); plan->execute(); if (vars[n]->getValue() != i) { @@ -665,7 +665,7 @@ class Planner { Variable* src = nullptr; Variable* dst = nullptr; - for (int32_t i = 1; i <= n; i++) { + for (int32_t i = 1; i <= n; i += 1) { src = Variable::value(i); dst = Variable::value(i); dests.append(dst); @@ -685,7 +685,7 @@ class Planner { } planner.change(scale, 5); - for (int32_t i = 0; i < n - 1; ++i) { + for (int32_t i = 0; i < n - 1; i += 1) { Variable* di = *dests.at(i); if (di->getValue() != (i + 1) * 5 + 1000) { throw Error("Projection test 3 failed!"); @@ -693,7 +693,7 @@ class Planner { } planner.change(offset, 2000); - for (int32_t i = 0; i < n - 1; ++i) { + for (int32_t i = 0; i < n - 1; i += 1) { Variable* di = *dests.at(i); if (di->getValue() != (i + 1) * 5 + 2000) { throw Error("Projection test 4 failed!"); diff --git a/benchmarks/C++/src/havlak.h b/benchmarks/C++/src/havlak.h index 014b17ff..d23b1bd4 100644 --- a/benchmarks/C++/src/havlak.h +++ b/benchmarks/C++/src/havlak.h @@ -293,7 +293,7 @@ class HavlakLoopFinder { // Start node is root of all other loops. _header[0] = 0; - for (int32_t w = size - 1; w >= 0; w--) { + for (int32_t w = size - 1; w >= 0; w -= 1) { // this is 'P' in Havlak's paper Vector nodePool{}; diff --git a/benchmarks/C++/src/permute.h b/benchmarks/C++/src/permute.h index 50cea10d..8fc5e5d7 100644 --- a/benchmarks/C++/src/permute.h +++ b/benchmarks/C++/src/permute.h @@ -8,11 +8,11 @@ class Permute : public Benchmark { int32_t* v{nullptr}; void permute(int32_t n) { - count++; + count += 1; if (n != 0) { const int32_t n1 = n - 1; permute(n1); - for (int32_t i = n1; i >= 0; i--) { + for (int32_t i = n1; i >= 0; i -= 1) { swap(n1, i); permute(n1); swap(n1, i); diff --git a/benchmarks/C++/src/queens.h b/benchmarks/C++/src/queens.h index ae72ad49..4a6ba733 100644 --- a/benchmarks/C++/src/queens.h +++ b/benchmarks/C++/src/queens.h @@ -32,7 +32,7 @@ class Queens : public Benchmark { } bool place_queen(int32_t c) { - for (int32_t r = 0; r < 8; r++) { + for (int32_t r = 0; r < 8; r += 1) { if (get_row_column(r, c)) { queen_rows[r] = c; set_row_column(r, c, false); @@ -63,7 +63,7 @@ class Queens : public Benchmark { public: void* benchmark() override { bool result = true; - for (int32_t i = 0; i < 10; i++) { + for (int32_t i = 0; i < 10; i += 1) { result = result && queens(); } return reinterpret_cast(result); diff --git a/benchmarks/C++/src/richards.h b/benchmarks/C++/src/richards.h index 1512de2e..e8fcacd7 100644 --- a/benchmarks/C++/src/richards.h +++ b/benchmarks/C++/src/richards.h @@ -136,7 +136,7 @@ class IdleTaskDataRecord : public RBObject { class Packet : public RBObject { public: - static const int DATA_SIZE = 4; + static const int32_t DATA_SIZE = 4; private: Packet* _link; @@ -387,7 +387,7 @@ class Scheduler : public RBObject { (HANDLER_A == data->getDestination()) ? HANDLER_B : HANDLER_A); work->setIdentity(data->getDestination()); work->setDatum(0); - for (int i = 0; i < Packet::DATA_SIZE; i++) { + for (int32_t i = 0; i < Packet::DATA_SIZE; i += 1) { data->setCount(data->getCount() + 1); if (data->getCount() > 26) { data->setCount(1); diff --git a/benchmarks/C++/src/run.h b/benchmarks/C++/src/run.h index 1da01a32..1f6e1157 100644 --- a/benchmarks/C++/src/run.h +++ b/benchmarks/C++/src/run.h @@ -119,7 +119,7 @@ class Run { } void do_runs(Benchmark* const bench) { - for (int32_t i = 0; i < num_iterations; i++) { + for (int32_t i = 0; i < num_iterations; i += 1) { measure(bench); } } diff --git a/benchmarks/C++/src/sieve.h b/benchmarks/C++/src/sieve.h index 3d715c7a..3703aab6 100644 --- a/benchmarks/C++/src/sieve.h +++ b/benchmarks/C++/src/sieve.h @@ -23,9 +23,9 @@ class Sieve : public Benchmark { int32_t sieve(std::array flags, int32_t size) { int32_t prime_count = 0; - for (int32_t i = 2; i <= size; i++) { + for (int32_t i = 2; i <= size; i += 1) { if (flags[i - 1]) { - prime_count++; + prime_count += 1; int k = i + i; while (k <= size) { flags[k - 1] = false; diff --git a/benchmarks/C++/src/som/dictionary.h b/benchmarks/C++/src/som/dictionary.h index 56ad916c..3e98781c 100644 --- a/benchmarks/C++/src/som/dictionary.h +++ b/benchmarks/C++/src/som/dictionary.h @@ -121,7 +121,7 @@ class Dictionary { } void removeAll() { - for (int32_t i = 0; i < _capacity; i++) { + for (int32_t i = 0; i < _capacity; i += 1) { Entry* current = _buckets[i]; while (current != nullptr) { Entry* toBeDeleted = current; @@ -136,7 +136,7 @@ class Dictionary { [[nodiscard]] Vector* getKeys() { auto* keys = new Vector(); - for (int32_t i = 0; i < _capacity; i++) { + for (int32_t i = 0; i < _capacity; i += 1) { Entry* current = _buckets[i]; while (current != nullptr) { keys->append(current->_key); @@ -149,7 +149,7 @@ class Dictionary { [[nodiscard]] Vector* getValues() { auto* values = new Vector(_size); - for (int32_t i = 0; i < _capacity; i++) { + for (int32_t i = 0; i < _capacity; i += 1) { Entry* current = _buckets[i]; while (current != nullptr) { values->append(current->_value); @@ -160,7 +160,7 @@ class Dictionary { } void destroyValues() { - for (int32_t i = 0; i < _capacity; i++) { + for (int32_t i = 0; i < _capacity; i += 1) { Entry* current = _buckets[i]; while (current != nullptr) { delete current->_value; @@ -213,7 +213,7 @@ class Dictionary { } void transferEntries(Entry** oldStorage, int32_t oldCapacity) { - for (int32_t i = 0; i < oldCapacity; i++) { + for (int32_t i = 0; i < oldCapacity; i += 1) { Entry* current = oldStorage[i]; if (current != nullptr) { oldStorage[i] = nullptr; diff --git a/benchmarks/C++/src/som/vector.h b/benchmarks/C++/src/som/vector.h index 7c6f7402..fd6cccbb 100644 --- a/benchmarks/C++/src/som/vector.h +++ b/benchmarks/C++/src/som/vector.h @@ -89,7 +89,7 @@ class Vector { ~Vector() { delete[] storage; } void destroyValues() { - for (size_t i = _firstIdx; i < _lastIdx; i++) { + for (size_t i = _firstIdx; i < _lastIdx; i += 1) { delete storage[i]; } } @@ -108,7 +108,7 @@ class Vector { newLength *= 2; } E* newStorage = new E[newLength]; - for (size_t i = 0; i < _lastIdx; i++) { + for (size_t i = 0; i < _lastIdx; i += 1) { newStorage[i] = storage[i]; } delete[] storage; @@ -126,7 +126,7 @@ class Vector { // Need to expand _capacity first _capacity *= 2; E* newStorage = new E[_capacity]; - for (size_t i = 0; i < _lastIdx; i++) { + for (size_t i = 0; i < _lastIdx; i += 1) { newStorage[i] = storage[i]; } delete[] storage; @@ -134,19 +134,19 @@ class Vector { } storage[_lastIdx] = elem; - _lastIdx++; + _lastIdx += 1; } [[nodiscard]] bool isEmpty() const { return _lastIdx == _firstIdx; } void forEach(const std::function& fn) const { - for (size_t i = _firstIdx; i < _lastIdx; i++) { + for (size_t i = _firstIdx; i < _lastIdx; i += 1) { fn(storage[i]); } } bool hasSome(const std::function& fn) const { - for (size_t i = _firstIdx; i < _lastIdx; i++) { + for (size_t i = _firstIdx; i < _lastIdx; i += 1) { if (fn(storage[i])) { return true; } @@ -155,7 +155,7 @@ class Vector { } E getOne(const std::function& fn) const { - for (size_t i = _firstIdx; i < _lastIdx; i++) { + for (size_t i = _firstIdx; i < _lastIdx; i += 1) { const E& e = storage[i]; if (fn(e)) { return e; @@ -177,19 +177,19 @@ class Vector { return nullptr; // Return a default-constructed object for an empty // vector } - _firstIdx++; + _firstIdx += 1; return storage[_firstIdx - 1]; } bool remove(const E& obj) { bool found = false; size_t newLast = _firstIdx; - for (size_t i = _firstIdx; i < _lastIdx; i++) { + for (size_t i = _firstIdx; i < _lastIdx; i += 1) { if (storage[i] == obj) { found = true; } else { storage[newLast] = storage[i]; - newLast++; + newLast += 1; } } _lastIdx = newLast; diff --git a/benchmarks/C++/src/storage.h b/benchmarks/C++/src/storage.h index d239f484..c4327651 100644 --- a/benchmarks/C++/src/storage.h +++ b/benchmarks/C++/src/storage.h @@ -36,13 +36,13 @@ class Storage : public Benchmark { private: ArrayTree* build_tree_depth(int32_t depth, Random& random) { - count++; + count += 1; if (depth == 1) { return new ArrayTree[random.next() % 10 + 1]; } auto* arr = new ArrayTree[4]; - for (size_t i = 0; i < 4; i++) { + for (size_t i = 0; i < 4; i += 1) { arr[i].children = build_tree_depth(depth - 1, random); } return arr; diff --git a/benchmarks/C++/src/towers.h b/benchmarks/C++/src/towers.h index 8ff1c68f..aa5c3ece 100644 --- a/benchmarks/C++/src/towers.h +++ b/benchmarks/C++/src/towers.h @@ -75,11 +75,11 @@ class Towers : public Benchmark { void move_top_disk(int32_t from_pile, int32_t to_pile) { push_disk(pop_disk_from(from_pile), to_pile); - moves_done++; + moves_done += 1; } void build_tower_at(int32_t pile, int32_t disks) { - for (int32_t i = disks; i >= 0; i--) { + for (int32_t i = disks; i >= 0; i -= 1) { push_disk(new TowersDisk(i), pile); } } From cfd1180563a2124bb8c733a75ad3b039962fd43b Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 10 Jan 2024 14:50:26 +0000 Subject: [PATCH 21/40] [C++] Added port of Set and IdentitySet which were missing Signed-off-by: Stefan Marr --- benchmarks/C++/src/som/identity_set.h | 16 ++++++++ benchmarks/C++/src/som/set.h | 57 +++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 benchmarks/C++/src/som/identity_set.h create mode 100644 benchmarks/C++/src/som/set.h diff --git a/benchmarks/C++/src/som/identity_set.h b/benchmarks/C++/src/som/identity_set.h new file mode 100644 index 00000000..99a2f853 --- /dev/null +++ b/benchmarks/C++/src/som/identity_set.h @@ -0,0 +1,16 @@ +#pragma once + +#include "set.h" + +#include + +template +class IdentitySet : public Set { + public: + explicit IdentitySet() = default; + explicit IdentitySet(size_t size) : Set(size) {} + + bool contains(E& obj) { + return hasSome([&obj](const E& e) { return e == obj; }); + } +}; diff --git a/benchmarks/C++/src/som/set.h b/benchmarks/C++/src/som/set.h new file mode 100644 index 00000000..a3e14fbc --- /dev/null +++ b/benchmarks/C++/src/som/set.h @@ -0,0 +1,57 @@ +#pragma once + +#include + +#include "vector.h" + +constexpr const int32_t INITIAL_SIZE = 10; + +template +class Set { + private: + Vector items{INITIAL_SIZE}; + + public: + explicit Set() = default; + explicit Set(size_t size) : items(size) {} + + [[nodiscard]] size_t size() const { return items.size(); } + + void forEach(const std::function& fn) const { + items.forEach(fn); + } + + [[nodiscard]] bool hasSome(const std::function& fn) const { + return items.hasSome(fn); + } + + [[nodiscard]] E getOne(const std::function& fn) const { + return items.getOne(fn); + } + + void add(E obj) { + if (!contains(obj)) { + items.append(obj); + } + } + + template + [[nodiscard]] Vector* collect(const std::function& fn) const { + auto* coll = new Vector(); + forEach([&coll, &fn](const E& e) { coll->append(fn(e)); }); + return coll; + } + + [[nodiscard]] bool contains(E& obj) { + return hasSome([&obj](const E& e) { + // C++17 compile-time magic to avoid issues with non-pointer types + if constexpr (std::is_same_v) { + return e == obj; + } else { + return e->equal(obj); + } + }); + } + + void removeAll() { items.removeAll(); } +}; From 8a6f8d62c8d85ff498c4ab9a94e3ec9061b0fa69 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 10 Jan 2024 17:44:59 +0000 Subject: [PATCH 22/40] [C++] Add missing imports and fix lint issues Signed-off-by: Stefan Marr --- benchmarks/C++/src/bounce.h | 2 ++ benchmarks/C++/src/cd.h | 8 +++++--- benchmarks/C++/src/deltablue.cpp | 5 +++++ benchmarks/C++/src/harness.cpp | 1 + benchmarks/C++/src/havlak.h | 6 ++---- benchmarks/C++/src/nbody.h | 6 ++---- benchmarks/C++/src/permute.h | 2 +- benchmarks/C++/src/richards.h | 6 +++--- benchmarks/C++/src/som/vector.h | 6 +++--- 9 files changed, 24 insertions(+), 18 deletions(-) diff --git a/benchmarks/C++/src/bounce.h b/benchmarks/C++/src/bounce.h index 1e3c8dcc..7ef05b09 100644 --- a/benchmarks/C++/src/bounce.h +++ b/benchmarks/C++/src/bounce.h @@ -3,6 +3,8 @@ #include "benchmark.h" #include "som/random.h" +#include + class Ball { private: int32_t x; diff --git a/benchmarks/C++/src/cd.h b/benchmarks/C++/src/cd.h index a69aea1a..4e7ef5f4 100644 --- a/benchmarks/C++/src/cd.h +++ b/benchmarks/C++/src/cd.h @@ -1,6 +1,9 @@ #pragma once +#include #include +#include + #include "benchmark.h" #include "som/error.h" #include "som/vector.h" @@ -936,9 +939,8 @@ class CD : public Benchmark { return actualCollisions == 42; } - std::cout << "No verification result for " << numAircrafts << " found" - << std::endl; - std::cout << "Result is: " << actualCollisions << std::endl; + std::cout << "No verification result for " << numAircrafts << " found\n"; + std::cout << "Result is: " << actualCollisions << "\n"; return false; } diff --git a/benchmarks/C++/src/deltablue.cpp b/benchmarks/C++/src/deltablue.cpp index 198ba8b1..bbfa6154 100644 --- a/benchmarks/C++/src/deltablue.cpp +++ b/benchmarks/C++/src/deltablue.cpp @@ -1,4 +1,9 @@ #include "deltablue.h" +#include "som/dictionary.h" +#include "som/error.h" +#include "som/identity_dictionary.h" + +#include // Set static member variable const Sym Strength::ABSOLUTE_STRONGEST(0); diff --git a/benchmarks/C++/src/harness.cpp b/benchmarks/C++/src/harness.cpp index 36af6a19..1b5a6485 100644 --- a/benchmarks/C++/src/harness.cpp +++ b/benchmarks/C++/src/harness.cpp @@ -1,4 +1,5 @@ #include +#include #include "run.h" diff --git a/benchmarks/C++/src/havlak.h b/benchmarks/C++/src/havlak.h index d23b1bd4..7829f99b 100644 --- a/benchmarks/C++/src/havlak.h +++ b/benchmarks/C++/src/havlak.h @@ -7,7 +7,6 @@ #include "som/identity_set.h" using std::cout; -using std::endl; class BasicBlock : public CustomHash { private: @@ -573,9 +572,8 @@ class Havlak : public Benchmark { return r[0] == 1605 && r[1] == 5213; } - cout << "No verification result for " << innerIterations << " found" - << endl; - cout << "Result is: " << r[0] << ", " << r[1] << endl; + cout << "No verification result for " << innerIterations << " found\n"; + cout << "Result is: " << r[0] << ", " << r[1] << "\n"; return false; } diff --git a/benchmarks/C++/src/nbody.h b/benchmarks/C++/src/nbody.h index 13cb862b..5d8895d6 100644 --- a/benchmarks/C++/src/nbody.h +++ b/benchmarks/C++/src/nbody.h @@ -4,7 +4,6 @@ #include "som/error.h" using std::cout; -using std::endl; class Body { private: @@ -180,9 +179,8 @@ class NBody : public Benchmark { return result == -0.16907495402506745; } - cout << "No verification result for " << innerIterations << " found" - << endl; - cout << "Result is: " << result << endl; + cout << "No verification result for " << innerIterations << " found\n"; + cout << "Result is: " << result << "\n"; return false; } diff --git a/benchmarks/C++/src/permute.h b/benchmarks/C++/src/permute.h index 8fc5e5d7..4deae81e 100644 --- a/benchmarks/C++/src/permute.h +++ b/benchmarks/C++/src/permute.h @@ -20,7 +20,7 @@ class Permute : public Benchmark { } } - void swap(int32_t i, int32_t j) { + void swap(int32_t i, int32_t j) noexcept { const int32_t tmp = v[i]; v[i] = v[j]; v[j] = tmp; diff --git a/benchmarks/C++/src/richards.h b/benchmarks/C++/src/richards.h index e8fcacd7..c151195d 100644 --- a/benchmarks/C++/src/richards.h +++ b/benchmarks/C++/src/richards.h @@ -5,11 +5,11 @@ #include "som/error.h" #include +#include #include #include using std::cout; -using std::endl; class Packet; class TaskControlBlock; @@ -467,10 +467,10 @@ class Scheduler : public RBObject { void trace(int32_t id) { _layout = _layout - 1; if (0 >= _layout) { - cout << endl; + cout << "\n"; _layout = 50; } - cout << id << endl; + cout << id << "\n"; } TaskControlBlock* markWaiting() { diff --git a/benchmarks/C++/src/som/vector.h b/benchmarks/C++/src/som/vector.h index fd6cccbb..f3b01513 100644 --- a/benchmarks/C++/src/som/vector.h +++ b/benchmarks/C++/src/som/vector.h @@ -212,13 +212,13 @@ class Vector { } private: - static void swap(E*, size_t, size_t) { - std::cerr << "swap not implemented" << std::endl; + static void swap(E*, size_t, size_t) noexcept { + std::cerr << "swap not implemented\n"; exit(1); } void defaultSort(size_t, size_t) { - std::cerr << "defaultSort not implemented" << std::endl; + std::cerr << "defaultSort not implemented\n"; exit(1); } }; From 1b2ab12e1d6767092051835be173668ec0a5a568 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 10 Jan 2024 18:39:50 +0000 Subject: [PATCH 23/40] [C++] Use std::any instead of void* Signed-off-by: Stefan Marr --- benchmarks/C++/src/benchmark.h | 5 +++-- benchmarks/C++/src/bounce.h | 9 +++++---- benchmarks/C++/src/cd.h | 7 +++++-- benchmarks/C++/src/deltablue.h | 6 ++++-- benchmarks/C++/src/havlak.h | 7 +++++-- benchmarks/C++/src/json.h | 10 +++++----- benchmarks/C++/src/list.h | 8 ++++---- benchmarks/C++/src/mandelbrot.h | 5 +++-- benchmarks/C++/src/nbody.h | 9 +++++++-- benchmarks/C++/src/permute.h | 10 ++++++---- benchmarks/C++/src/queens.h | 9 +++++---- benchmarks/C++/src/richards.h | 10 +++++----- benchmarks/C++/src/sieve.h | 11 ++++++----- benchmarks/C++/src/storage.h | 9 +++++---- benchmarks/C++/src/towers.h | 9 +++++---- 15 files changed, 73 insertions(+), 51 deletions(-) diff --git a/benchmarks/C++/src/benchmark.h b/benchmarks/C++/src/benchmark.h index 5c12762f..7d0f9c03 100644 --- a/benchmarks/C++/src/benchmark.h +++ b/benchmarks/C++/src/benchmark.h @@ -1,13 +1,14 @@ #pragma once +#include #include class Benchmark { public: virtual ~Benchmark() = default; - virtual void* benchmark() = 0; - virtual bool verify_result(void* result) = 0; + virtual std::any benchmark() = 0; + virtual bool verify_result(std::any result) = 0; virtual bool inner_benchmark_loop(int32_t inner_iterations) { for (int32_t i = 0; i < inner_iterations; i += 1) { diff --git a/benchmarks/C++/src/bounce.h b/benchmarks/C++/src/bounce.h index 7ef05b09..f2839daa 100644 --- a/benchmarks/C++/src/bounce.h +++ b/benchmarks/C++/src/bounce.h @@ -3,6 +3,7 @@ #include "benchmark.h" #include "som/random.h" +#include #include class Ball { @@ -60,7 +61,7 @@ class Ball { class Bounce : public Benchmark { public: - void* benchmark() override { + std::any benchmark() override { Random random; const int32_t ball_count = 100; @@ -79,10 +80,10 @@ class Bounce : public Benchmark { } } } - return reinterpret_cast(static_cast(bounces)); + return bounces; } - bool verify_result(void* result) override { - return 1331 == static_cast(reinterpret_cast(result)); + bool verify_result(std::any result) override { + return 1331 == std::any_cast(result); } }; diff --git a/benchmarks/C++/src/cd.h b/benchmarks/C++/src/cd.h index 4e7ef5f4..75525f15 100644 --- a/benchmarks/C++/src/cd.h +++ b/benchmarks/C++/src/cd.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -944,6 +945,8 @@ class CD : public Benchmark { return false; } - void* benchmark() override { throw Error("Should never be reached"); } - bool verify_result(void*) override { throw Error("Should never be reached"); } + std::any benchmark() override { throw Error("Should never be reached"); } + bool verify_result(std::any) override { + throw Error("Should never be reached"); + } }; diff --git a/benchmarks/C++/src/deltablue.h b/benchmarks/C++/src/deltablue.h index 21b3b456..45f75acf 100644 --- a/benchmarks/C++/src/deltablue.h +++ b/benchmarks/C++/src/deltablue.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "benchmark.h" #include "memory/object_tracker.h" #include "som/error.h" @@ -712,7 +714,7 @@ class DeltaBlue : public Benchmark { return true; } - void* benchmark() override { return nullptr; } + std::any benchmark() override { return nullptr; } - bool verify_result(void*) override { return false; } + bool verify_result(std::any) override { return false; } }; diff --git a/benchmarks/C++/src/havlak.h b/benchmarks/C++/src/havlak.h index 7829f99b..e57e8ab6 100644 --- a/benchmarks/C++/src/havlak.h +++ b/benchmarks/C++/src/havlak.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -578,7 +579,9 @@ class Havlak : public Benchmark { return false; } - void* benchmark() override { throw Error("Should never be reached"); } + std::any benchmark() override { throw Error("Should never be reached"); } - bool verify_result(void*) override { throw Error("Should never be reached"); } + bool verify_result(std::any) override { + throw Error("Should never be reached"); + } }; diff --git a/benchmarks/C++/src/json.h b/benchmarks/C++/src/json.h index 0c4d7d95..0eeeda13 100644 --- a/benchmarks/C++/src/json.h +++ b/benchmarks/C++/src/json.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "benchmark.h" @@ -976,11 +977,10 @@ class JsonPureStringParser { class Json : public Benchmark { private: public: - void* benchmark() override { + std::any benchmark() override { JsonPureStringParser parser{rapBenchmarkMinified}; const JsonValue* const result = parser.parse(); - return const_cast( - result); // TODO make benchmark return const void* or std::any or so + return result; } bool has_expected_content(const JsonValue* result) { @@ -998,8 +998,8 @@ class Json : public Benchmark { return resultArray->size() == 156; } - bool verify_result(void* r) override { - auto* const result = reinterpret_cast(r); + bool verify_result(std::any r) override { + auto* const result = std::any_cast(r); const bool doesVerify = has_expected_content(result); delete result; return doesVerify; diff --git a/benchmarks/C++/src/list.h b/benchmarks/C++/src/list.h index d6805e8a..2513f388 100644 --- a/benchmarks/C++/src/list.h +++ b/benchmarks/C++/src/list.h @@ -33,7 +33,7 @@ class Element { class List : public Benchmark { public: - void* benchmark() override { + std::any benchmark() override { Element* x = makeList(15); Element* y = makeList(10); Element* z = makeList(6); @@ -44,7 +44,7 @@ class List : public Benchmark { delete x; delete y; delete z; - return reinterpret_cast(static_cast(l)); + return l; } private: @@ -79,7 +79,7 @@ class List : public Benchmark { return z; } - bool verify_result(void* result) override { - return 10 == static_cast(reinterpret_cast(result)); + bool verify_result(std::any result) override { + return 10 == std::any_cast(result); } }; diff --git a/benchmarks/C++/src/mandelbrot.h b/benchmarks/C++/src/mandelbrot.h index a2a7fa3c..73abc53c 100644 --- a/benchmarks/C++/src/mandelbrot.h +++ b/benchmarks/C++/src/mandelbrot.h @@ -1,13 +1,14 @@ #pragma once +#include #include #include "benchmark.h" class Mandelbrot : public Benchmark { public: - void* benchmark() override { return nullptr; }; - bool verify_result(void*) override { return false; }; + std::any benchmark() override { return nullptr; }; + bool verify_result(std::any) override { return false; }; bool inner_benchmark_loop(int32_t inner_iterations) override { return verify_result(mandelbrot(inner_iterations), inner_iterations); diff --git a/benchmarks/C++/src/nbody.h b/benchmarks/C++/src/nbody.h index 5d8895d6..5d26c863 100644 --- a/benchmarks/C++/src/nbody.h +++ b/benchmarks/C++/src/nbody.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "benchmark.h" #include "som/error.h" @@ -193,6 +195,9 @@ class NBody : public Benchmark { return verify_result(system.energy(), innerIterations); } - void* benchmark() override { throw Error("Should never be reached"); } - bool verify_result(void*) override { throw Error("Should never be reached"); } + + std::any benchmark() override { throw Error("Should never be reached"); } + bool verify_result(std::any) override { + throw Error("Should never be reached"); + } }; diff --git a/benchmarks/C++/src/permute.h b/benchmarks/C++/src/permute.h index 4deae81e..ae046a73 100644 --- a/benchmarks/C++/src/permute.h +++ b/benchmarks/C++/src/permute.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "benchmark.h" class Permute : public Benchmark { @@ -27,15 +29,15 @@ class Permute : public Benchmark { } public: - void* benchmark() override { + std::any benchmark() override { count = 0; v = new int32_t[6]; permute(6); delete[] v; - return reinterpret_cast(static_cast(count)); + return count; } - bool verify_result(void* result) override { - return 8660 == static_cast(reinterpret_cast(result)); + bool verify_result(std::any result) override { + return 8660 == std::any_cast(result); } }; diff --git a/benchmarks/C++/src/queens.h b/benchmarks/C++/src/queens.h index 4a6ba733..2bd983d5 100644 --- a/benchmarks/C++/src/queens.h +++ b/benchmarks/C++/src/queens.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "benchmark.h" @@ -61,15 +62,15 @@ class Queens : public Benchmark { } public: - void* benchmark() override { + std::any benchmark() override { bool result = true; for (int32_t i = 0; i < 10; i += 1) { result = result && queens(); } - return reinterpret_cast(result); + return result; } - bool verify_result(void* result) override { - return static_cast(reinterpret_cast(result)); + bool verify_result(std::any result) override { + return std::any_cast(result); } }; diff --git a/benchmarks/C++/src/richards.h b/benchmarks/C++/src/richards.h index c151195d..8d09591e 100644 --- a/benchmarks/C++/src/richards.h +++ b/benchmarks/C++/src/richards.h @@ -4,6 +4,7 @@ #include "memory/object_tracker.h" #include "som/error.h" +#include #include #include #include @@ -496,17 +497,16 @@ class Scheduler : public RBObject { class Richards : public Benchmark { public: - bool verify_result(void* result) override { - const bool result_cast = - static_cast(reinterpret_cast(result)); + bool verify_result(std::any result) override { + const bool result_cast = std::any_cast(result); return result_cast; } - void* benchmark() override { + std::any benchmark() override { auto* scheduler = new Scheduler(); const bool result = scheduler->start(); ObjectTracker::releaseAll(); - return reinterpret_cast(static_cast(result)); + return result; } }; diff --git a/benchmarks/C++/src/sieve.h b/benchmarks/C++/src/sieve.h index 3703aab6..935a10e2 100644 --- a/benchmarks/C++/src/sieve.h +++ b/benchmarks/C++/src/sieve.h @@ -1,21 +1,22 @@ #pragma once +#include + #include "benchmark.h" class Sieve : public Benchmark { public: - void* benchmark() override { + std::any benchmark() override { const int32_t num_flags = 5000; std::array flags{}; std::fill_n(flags.begin(), num_flags, true); - return reinterpret_cast( - static_cast(sieve(flags, 5000))); + return sieve(flags, 5000); } - bool verify_result(void* result) override { - return 669 == static_cast(reinterpret_cast(result)); + bool verify_result(std::any result) override { + return 669 == std::any_cast(result); } private: diff --git a/benchmarks/C++/src/storage.h b/benchmarks/C++/src/storage.h index c4327651..58039d88 100644 --- a/benchmarks/C++/src/storage.h +++ b/benchmarks/C++/src/storage.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "benchmark.h" @@ -20,18 +21,18 @@ class Storage : public Benchmark { public: Storage() = default; - void* benchmark() override { + std::any benchmark() override { Random random; count = 0; ArrayTree* result = build_tree_depth(7, random); delete[] result; - return reinterpret_cast(static_cast(count)); + return count; } - bool verify_result(void* result) override { - return 5461 == static_cast(reinterpret_cast(result)); + bool verify_result(std::any result) override { + return 5461 == std::any_cast(result); } private: diff --git a/benchmarks/C++/src/towers.h b/benchmarks/C++/src/towers.h index aa5c3ece..a0104228 100644 --- a/benchmarks/C++/src/towers.h +++ b/benchmarks/C++/src/towers.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -32,7 +33,7 @@ class Towers : public Benchmark { int32_t moves_done{0}; public: - void* benchmark() override { + std::any benchmark() override { piles = std::array(); build_tower_at(0, 13); moves_done = 0; @@ -42,11 +43,11 @@ class Towers : public Benchmark { delete disk; } - return reinterpret_cast(static_cast(moves_done)); + return moves_done; } - bool verify_result(void* result) override { - return 8191 == static_cast(reinterpret_cast(result)); + bool verify_result(std::any result) override { + return 8191 == std::any_cast(result); } private: From 73891a4e0d6cc13595c521e9e8a78d93f62929ca Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Wed, 10 Jan 2024 21:21:53 +0000 Subject: [PATCH 24/40] [C++] Make hash and size related things unsigned Signed-off-by: Stefan Marr --- benchmarks/C++/src/deltablue.h | 6 +- benchmarks/C++/src/havlak.h | 4 +- benchmarks/C++/src/som/dictionary.h | 58 ++++++++++---------- benchmarks/C++/src/som/identity_dictionary.h | 8 +-- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/benchmarks/C++/src/deltablue.h b/benchmarks/C++/src/deltablue.h index 45f75acf..5da3e8d1 100644 --- a/benchmarks/C++/src/deltablue.h +++ b/benchmarks/C++/src/deltablue.h @@ -12,13 +12,13 @@ enum Direction { FORWARD, BACKWARD, NONE }; class Sym : public CustomHash { private: - int32_t hash; + uint32_t hash; public: - explicit constexpr Sym(int32_t hash_value) noexcept : hash(hash_value){}; + explicit constexpr Sym(uint32_t hash_value) noexcept : hash(hash_value){}; ~Sym() override = default; - [[nodiscard]] int32_t customHash() const override { return hash; }; + [[nodiscard]] uint32_t customHash() const override { return hash; }; }; class Strength { diff --git a/benchmarks/C++/src/havlak.h b/benchmarks/C++/src/havlak.h index e57e8ab6..b34f78b4 100644 --- a/benchmarks/C++/src/havlak.h +++ b/benchmarks/C++/src/havlak.h @@ -13,7 +13,7 @@ class BasicBlock : public CustomHash { private: Vector _inEdges{2}; Vector _outEdges{2}; - int32_t _name; + uint32_t _name; public: explicit BasicBlock(int32_t name) : _name(name) {} @@ -22,7 +22,7 @@ class BasicBlock : public CustomHash { int32_t getNumPred() { return static_cast(_inEdges.size()); } void addOutEdge(BasicBlock* to) { _outEdges.append(to); } void addInEdge(BasicBlock* from) { _inEdges.append(from); } - [[nodiscard]] int32_t customHash() const override { return _name; } + [[nodiscard]] uint32_t customHash() const override { return _name; } bool equal(BasicBlock* other) const { return _name == other->_name; } }; diff --git a/benchmarks/C++/src/som/dictionary.h b/benchmarks/C++/src/som/dictionary.h index 3e98781c..e4ca57dc 100644 --- a/benchmarks/C++/src/som/dictionary.h +++ b/benchmarks/C++/src/som/dictionary.h @@ -7,7 +7,7 @@ class CustomHash { public: CustomHash() = default; virtual ~CustomHash() = default; - [[nodiscard]] virtual int32_t customHash() const = 0; + [[nodiscard]] virtual uint32_t customHash() const = 0; }; template @@ -29,33 +29,33 @@ class Dictionary { friend class Dictionary; private: - int32_t _hash; + uint32_t _hash; const CustomHash* const _key; V _value; Entry* _next; public: - Entry(int32_t h, const CustomHash* k, const V& v, Entry* n) + Entry(uint32_t h, const CustomHash* k, const V& v, Entry* n) : _hash(h), _key(k), _value(v), _next(n) {} virtual ~Entry() = default; - virtual bool match(int32_t h, const CustomHash* const k) { + virtual bool match(uint32_t h, const CustomHash* const k) { return _hash == h && _key == k; } [[nodiscard]] const CustomHash* getKey() const { return _key; } - [[nodiscard]] int32_t getHash() const { return _hash; } + [[nodiscard]] uint32_t getHash() const { return _hash; } }; - static const int32_t INITIAL_CAPACITY = 16; + static const uint32_t INITIAL_CAPACITY = 16; Entry** _buckets; - int32_t _size{0}; - int32_t _capacity; + uint32_t _size{0}; + uint32_t _capacity; public: - explicit Dictionary(int32_t capacity = INITIAL_CAPACITY) + explicit Dictionary(uint32_t capacity = INITIAL_CAPACITY) : _buckets(new Entry* [capacity] {}), _capacity(capacity) {} virtual ~Dictionary() { @@ -63,20 +63,20 @@ class Dictionary { delete[] _buckets; } - [[nodiscard]] int32_t getSize() const { return _size; } + [[nodiscard]] uint32_t getSize() const { return _size; } [[nodiscard]] bool isEmpty() const { return _size == 0; } - [[nodiscard]] int32_t hash(const CustomHash* key) const { + [[nodiscard]] uint32_t hash(const CustomHash* key) const { if (key == nullptr) { return 0; } - const int32_t h = key->customHash(); - return h ^ (h >> 16); + const uint32_t h = key->customHash(); + return h ^ (h >> 16U); } [[nodiscard]] bool containsKey(const CustomHash* key) const { - int32_t h = hash(key); + uint32_t h = hash(key); Entry* e = getBucket(h); while (e != nullptr) { @@ -89,7 +89,7 @@ class Dictionary { } V* at(const CustomHash* key) const { - const int32_t h = this->hash(key); + const uint32_t h = this->hash(key); Entry* e = getBucket(h); while (e != nullptr) { @@ -103,8 +103,8 @@ class Dictionary { } void atPut(const CustomHash* const key, const V& value) { - const int32_t h = hash(key); - const int32_t i = getBucketIdx(h); + const uint32_t h = hash(key); + const uint32_t i = getBucketIdx(h); Entry* current = _buckets[i]; @@ -121,7 +121,7 @@ class Dictionary { } void removeAll() { - for (int32_t i = 0; i < _capacity; i += 1) { + for (uint32_t i = 0; i < _capacity; i += 1) { Entry* current = _buckets[i]; while (current != nullptr) { Entry* toBeDeleted = current; @@ -136,7 +136,7 @@ class Dictionary { [[nodiscard]] Vector* getKeys() { auto* keys = new Vector(); - for (int32_t i = 0; i < _capacity; i += 1) { + for (uint32_t i = 0; i < _capacity; i += 1) { Entry* current = _buckets[i]; while (current != nullptr) { keys->append(current->_key); @@ -149,7 +149,7 @@ class Dictionary { [[nodiscard]] Vector* getValues() { auto* values = new Vector(_size); - for (int32_t i = 0; i < _capacity; i += 1) { + for (uint32_t i = 0; i < _capacity; i += 1) { Entry* current = _buckets[i]; while (current != nullptr) { values->append(current->_value); @@ -160,7 +160,7 @@ class Dictionary { } void destroyValues() { - for (int32_t i = 0; i < _capacity; i += 1) { + for (uint32_t i = 0; i < _capacity; i += 1) { Entry* current = _buckets[i]; while (current != nullptr) { delete current->_value; @@ -169,22 +169,22 @@ class Dictionary { } } - virtual Entry* newEntry(const CustomHash* key, V value, int32_t hash) { + virtual Entry* newEntry(const CustomHash* key, V value, uint32_t hash) { return new Entry(hash, key, value, nullptr); } private: - [[nodiscard]] int32_t getBucketIdx(int32_t hash) const { + [[nodiscard]] uint32_t getBucketIdx(uint32_t hash) const { return (_capacity - 1) & hash; } - [[nodiscard]] Entry* getBucket(int32_t hash) const { + [[nodiscard]] Entry* getBucket(uint32_t hash) const { return _buckets[getBucketIdx(hash)]; } void insertBucketEntry(const CustomHash* key, const V& value, - int32_t hash, + uint32_t hash, Entry* head) { Entry* current = head; @@ -204,7 +204,7 @@ class Dictionary { void resize() { Entry** oldStorage = _buckets; - const int32_t oldCapacity = _capacity; + const uint32_t oldCapacity = _capacity; _capacity *= 2; auto* newStorage = new Entry*[_capacity]; _buckets = newStorage; @@ -212,8 +212,8 @@ class Dictionary { delete[] oldStorage; } - void transferEntries(Entry** oldStorage, int32_t oldCapacity) { - for (int32_t i = 0; i < oldCapacity; i += 1) { + void transferEntries(Entry** oldStorage, uint32_t oldCapacity) { + for (uint32_t i = 0; i < oldCapacity; i += 1) { Entry* current = oldStorage[i]; if (current != nullptr) { oldStorage[i] = nullptr; @@ -226,7 +226,7 @@ class Dictionary { } } - void splitBucket(int32_t oldCapacity, int32_t idx, Entry* head) { + void splitBucket(uint32_t oldCapacity, uint32_t idx, Entry* head) { Entry* loHead = nullptr; Entry* loTail = nullptr; Entry* hiHead = nullptr; diff --git a/benchmarks/C++/src/som/identity_dictionary.h b/benchmarks/C++/src/som/identity_dictionary.h index f484dd60..6623d835 100644 --- a/benchmarks/C++/src/som/identity_dictionary.h +++ b/benchmarks/C++/src/som/identity_dictionary.h @@ -8,25 +8,25 @@ class IdentityDictionary : public Dictionary { private: class IdEntry : public Dictionary::Entry { public: - IdEntry(int hash, + IdEntry(uint32_t hash, const CustomHash* key, const V& value, typename Dictionary::Entry* next) : Dictionary::Entry(hash, key, value, next) {} ~IdEntry() override = default; - bool match(int h, const CustomHash* k) override { + bool match(uint32_t h, const CustomHash* k) override { return this->getHash() == h && this->getKey() == k; } }; public: - explicit IdentityDictionary(const int size) : Dictionary(size) {} + explicit IdentityDictionary(const uint32_t size) : Dictionary(size) {} IdentityDictionary() : Dictionary(Dictionary::INITIAL_CAPACITY) {} typename Dictionary::Entry* newEntry(const CustomHash* key, V value, - int32_t hash) override { + uint32_t hash) override { return new IdEntry(hash, key, value, nullptr); } }; From 25e36681b920dc8ae2bc03cf89caaa23a6abbac2 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 11 Jan 2024 00:17:21 +0000 Subject: [PATCH 25/40] [C++] Fix missing initialization in dictionary Signed-off-by: Stefan Marr --- benchmarks/C++/src/som/dictionary.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/C++/src/som/dictionary.h b/benchmarks/C++/src/som/dictionary.h index e4ca57dc..eaea91bd 100644 --- a/benchmarks/C++/src/som/dictionary.h +++ b/benchmarks/C++/src/som/dictionary.h @@ -206,7 +206,7 @@ class Dictionary { Entry** oldStorage = _buckets; const uint32_t oldCapacity = _capacity; _capacity *= 2; - auto* newStorage = new Entry*[_capacity]; + auto* newStorage = new Entry* [_capacity] {}; _buckets = newStorage; transferEntries(oldStorage, oldCapacity); delete[] oldStorage; From aeb3bec606c50903edf090b544ec5775dbfd6e3f Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 11 Jan 2024 11:38:25 +0000 Subject: [PATCH 26/40] [C++] Fix lint issues in deltablue and mandelbrot Signed-off-by: Stefan Marr --- benchmarks/C++/src/deltablue.h | 12 ++++++------ benchmarks/C++/src/mandelbrot.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/benchmarks/C++/src/deltablue.h b/benchmarks/C++/src/deltablue.h index 5da3e8d1..a6d5df49 100644 --- a/benchmarks/C++/src/deltablue.h +++ b/benchmarks/C++/src/deltablue.h @@ -15,10 +15,10 @@ class Sym : public CustomHash { uint32_t hash; public: - explicit constexpr Sym(uint32_t hash_value) noexcept : hash(hash_value){}; + explicit constexpr Sym(uint32_t hash_value) noexcept : hash(hash_value) {} ~Sym() override = default; - [[nodiscard]] uint32_t customHash() const override { return hash; }; + [[nodiscard]] uint32_t customHash() const override { return hash; } }; class Strength { @@ -300,7 +300,7 @@ class UnaryConstraint : public AbstractConstraint { // can't free _output here, because it is shared with other constraints ~UnaryConstraint() override = default; - bool isSatisfied() override { return _satisfied; }; + bool isSatisfied() override { return _satisfied; } void addToGraph() override { _output->addConstraint(this); @@ -342,7 +342,7 @@ class EditConstraint : public UnaryConstraint { : UnaryConstraint(v, strength, planner) { addConstraint(planner); // moved here from UnaryConstraint constructor to // make sure the right method is called - }; + } bool isInput() override { return true; } @@ -372,7 +372,7 @@ class EqualityConstraint : public BinaryConstraint { class Plan : public Vector { public: - Plan() : Vector(15){}; + Plan() : Vector(15) {} void execute() { forEach([&](AbstractConstraint* c) -> void { c->execute(); }); @@ -467,7 +467,7 @@ class StayConstraint : public UnaryConstraint { : UnaryConstraint(v, strength, planner) { addConstraint(planner); // moved here from UnaryConstraint constructor to // make sure the right method is called - }; + } void execute() override { // StayConstraints do nothing. diff --git a/benchmarks/C++/src/mandelbrot.h b/benchmarks/C++/src/mandelbrot.h index 73abc53c..f10cf536 100644 --- a/benchmarks/C++/src/mandelbrot.h +++ b/benchmarks/C++/src/mandelbrot.h @@ -7,8 +7,8 @@ class Mandelbrot : public Benchmark { public: - std::any benchmark() override { return nullptr; }; - bool verify_result(std::any) override { return false; }; + std::any benchmark() override { return nullptr; } + bool verify_result(std::any) override { return false; } bool inner_benchmark_loop(int32_t inner_iterations) override { return verify_result(mandelbrot(inner_iterations), inner_iterations); From fb2607073d1e25029e3cb47a779a7da5f4587f16 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 11 Jan 2024 11:40:04 +0000 Subject: [PATCH 27/40] [C++] Declare default copy constructor for Vector Signed-off-by: Stefan Marr --- benchmarks/C++/src/som/vector.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/benchmarks/C++/src/som/vector.h b/benchmarks/C++/src/som/vector.h index f3b01513..3e66e625 100644 --- a/benchmarks/C++/src/som/vector.h +++ b/benchmarks/C++/src/som/vector.h @@ -86,6 +86,8 @@ class Vector { explicit Vector() : Vector(50) {} // NOLINT + Vector(const Vector& other) = default; + ~Vector() { delete[] storage; } void destroyValues() { From ecb6ccf7270e534a3f573477baf27f7f4cf3c079 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 11 Jan 2024 16:41:11 +0000 Subject: [PATCH 28/40] [C++] Add C++ to test.conf and use input_sizes to test a range of inputs Signed-off-by: Stefan Marr --- test.conf | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/test.conf b/test.conf index ab154308..33b233fa 100644 --- a/test.conf +++ b/test.conf @@ -12,7 +12,7 @@ runs: benchmark_suites: test-som: gauge_adapter: RebenchLog - command: " -cp .:Core:CD:DeltaBlue:Havlak:Json:NBody:Richards:../../TruffleSOM/Smalltalk Harness.som %(benchmark)s 1 " + command: " -cp .:Core:CD:DeltaBlue:Havlak:Json:NBody:Richards:../../TruffleSOM/Smalltalk Harness.som %(benchmark)s 1 %(input)s " location: benchmarks/SOM max_invocation_time: 240 benchmarks: &BENCHMARKS @@ -28,23 +28,23 @@ benchmark_suites: extra_args: 1 - Bounce: - extra_args: 1 + input_sizes: [1, 100] - List: extra_args: 1 - Mandelbrot: - extra_args: 1 + input_sizes: [1, 500, 750] - NBody: extra_args: 1 - Permute: - extra_args: 1 + input_sizes: [1] - Queens: - extra_args: 1 + input_sizes: [1] - Sieve: - extra_args: 1 + input_sizes: [1] - Storage: - extra_args: 1 + input_sizes: [1] - Towers: - extra_args: 1 + input_sizes: [1] test-somns: gauge_adapter: RebenchLog @@ -100,6 +100,13 @@ benchmark_suites: max_invocation_time: 60 benchmarks: *BENCHMARKS + test-c++: + gauge_adapter: RebenchLog + location: benchmarks/C++ + command: " %(benchmark)s 1 %(input)s " + max_invocation_time: 60 + benchmarks: *BENCHMARKS + # VMs have a name and are specified by a path and the binary to be executed executors: Java: @@ -136,6 +143,8 @@ executors: executable: lua5.2 Python: executable: python + C++: + executable: harness experiments: test-som: @@ -172,3 +181,6 @@ experiments: test-python: suites: [test-python] executions: [Python] + test-c++: + suites: [test-c++] + executions: [C++] From f93caba95842b7b527a186d06fa2b1957371846b Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Thu, 11 Jan 2024 18:19:10 +0000 Subject: [PATCH 29/40] [C++] Add GitHub Actions setup - added style target Signed-off-by: Stefan Marr --- .github/workflows/ci.yml | 9 +++++++++ benchmarks/C++/build.sh | 32 +++++++++++++++++++++++++------- test.conf | 3 ++- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc2cbadd..092d69b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,7 @@ jobs: - { name: Ruby, id: ruby, folder: Ruby } - { name: Lua, id: lua, folder: Lua } - { name: Python, id: python, folder: Python } + - { name: C++, id: cpp, folder: C++ } name: ${{ matrix.name }} steps: @@ -39,6 +40,14 @@ jobs: ~/.asdf/bin/asdf plugin add awfy https://github.com/smarr/asdf-awfy.git if: matrix.id == 'squeak' || matrix.id == 'pharo' + - name: Install Clang 17 + run: | + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + sudo add-apt-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" + sudo apt-get update + sudo apt-get install -y clang-17 clang-format-17 clang-tidy-17 + if: matrix.id == 'cpp' + - name: Install Crystal if: matrix.id == 'crystal' uses: oprypin/install-crystal@v1 diff --git a/benchmarks/C++/build.sh b/benchmarks/C++/build.sh index 0de64738..bc0b5794 100755 --- a/benchmarks/C++/build.sh +++ b/benchmarks/C++/build.sh @@ -1,32 +1,51 @@ #!/bin/bash +SCRIPT_PATH="$(dirname "$0")" +source "$SCRIPT_PATH/../script.inc" # start by trying to find a suitable clang CMD_VERSION='-mp-17' if ! [ -x "$(command -v clang++$CMD_VERSION)" ]; then CMD_VERSION='-17' + if ! [ -x "$(command -v clang++$CMD_VERSION)" ]; then + CMD_VERSION='-15' + fi fi CMD="clang++$CMD_VERSION" +pushd "$SCRIPT_PATH" + +if [ "$1" = "style" ] +then + INFO Check Format + ./build.sh check-format + FMT_EXIT=$? + + INFO Run Lint + ./build.sh lint + LNT_EXIT=$? + exit $((FMT_EXIT + LNT_EXIT)) +fi + if [ "$1" = "format" ] then - CMD=clang-format - type -P "$CMD" || CMD=clang-format$CMD_VERSION + CMD=clang-format$CMD_VERSION + type -P "$CMD" || CMD=clang-format exec $CMD -i --style=file src/*.cpp src/*.h src/**/*.cpp src/**/*.h fi if [ "$1" = "check-format" ] then - CMD=clang-format - type -P "$CMD" || CMD=clang-format$CMD_VERSION + CMD=clang-format$CMD_VERSION + type -P "$CMD" || CMD=clang-format exec $CMD --style=file --dry-run --Werror src/*.cpp src/*.h src/**/*.cpp src/**/*.h fi if [ "$1" = "lint" ] then - CMD=clang-tidy - type -P "$CMD" || CMD=clang-tidy$CMD_VERSION + CMD=clang-tidy$CMD_VERSION + type -P "$CMD" || CMD=clang-tidy exec $CMD --config-file=.clang-tidy -header-filter=.* src/*.cpp fi @@ -66,7 +85,6 @@ then OPT='-O3' echo Bulding with pedantic warnings and $OPT optimizations else - echo Bulding with $OPT optimizations SANATIZE='' fi diff --git a/test.conf b/test.conf index 33b233fa..1d6b9249 100644 --- a/test.conf +++ b/test.conf @@ -144,6 +144,7 @@ executors: Python: executable: python C++: + path: benchmarks/C++ executable: harness experiments: @@ -181,6 +182,6 @@ experiments: test-python: suites: [test-python] executions: [Python] - test-c++: + test-cpp: suites: [test-c++] executions: [C++] From a1551d9dac030298030e82750dc6f4b3827f51a3 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 11 Feb 2024 00:42:49 +0000 Subject: [PATCH 30/40] Remove the need of garbage collection from the description of the core language And some minor edits. Signed-off-by: Stefan Marr --- docs/core-language.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/core-language.md b/docs/core-language.md index 9df8e1f3..78dcde9b 100644 --- a/docs/core-language.md +++ b/docs/core-language.md @@ -33,9 +33,9 @@ permitted. ## The *Core* Languages -While our initial intention is to compare object-oriented (OO) languages, the +While our intention is to compare object-oriented (OO) languages, the benchmarks could be implemented on other languages as well as long as for -instance the polymorphic nature of the benchmark code can be expressed somehow. +instance the polymorphic nature of the benchmark code can be expressed. #### Required Abstractions @@ -47,8 +47,6 @@ The set of required concepts is: - basic array-like abstractions, ideally with a fixed size - strings, with access to individual characters, support for mutation is not required - - garbage collection, currently benchmarks rely on it and we do not yet have - variants that do manual memory management For some languages, a mapping of these abstraction is not trivial and we define [guidelines](guidelines.md) for these cases. For example, Java does not support From b2ca60f1cf47baf17c020001991ca7655b6f6100 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 6 Feb 2024 23:23:46 +0000 Subject: [PATCH 31/40] [C++] Change Vector to initialize array lazily Signed-off-by: Stefan Marr --- benchmarks/C++/src/som/set.h | 2 -- benchmarks/C++/src/som/vector.h | 34 +++++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/benchmarks/C++/src/som/set.h b/benchmarks/C++/src/som/set.h index a3e14fbc..c17b06be 100644 --- a/benchmarks/C++/src/som/set.h +++ b/benchmarks/C++/src/som/set.h @@ -4,8 +4,6 @@ #include "vector.h" -constexpr const int32_t INITIAL_SIZE = 10; - template class Set { private: diff --git a/benchmarks/C++/src/som/vector.h b/benchmarks/C++/src/som/vector.h index 3e66e625..1a62e503 100644 --- a/benchmarks/C++/src/som/vector.h +++ b/benchmarks/C++/src/som/vector.h @@ -6,6 +6,8 @@ #include #include +constexpr const size_t INITIAL_SIZE = 10; + template class Vector { private: @@ -82,9 +84,10 @@ class Vector { return v; } - explicit Vector(size_t size) : storage(new E[size]), _capacity(size) {} + explicit Vector(size_t size) + : storage(size == 0 ? nullptr : new E[size]), _capacity(size) {} - explicit Vector() : Vector(50) {} // NOLINT + explicit Vector() : Vector(0) {} // NOLINT Vector(const Vector& other) = default; @@ -97,14 +100,17 @@ class Vector { } [[nodiscard]] E* at(size_t idx) const { - if (idx >= _lastIdx - _firstIdx) { + if (storage == nullptr || idx >= _lastIdx - _firstIdx) { return nullptr; } return &storage[_firstIdx + idx]; } void atPut(size_t idx, const E& val) { - if (idx >= _lastIdx - _firstIdx) { + if (storage == nullptr) { + _capacity = std::max(idx + 1, INITIAL_SIZE); + storage = new E[_capacity]; + } else if (idx >= _lastIdx - _firstIdx) { size_t newLength = _capacity; while (newLength <= idx + _firstIdx) { newLength *= 2; @@ -124,7 +130,10 @@ class Vector { } void append(const E& elem) { - if (_lastIdx >= _capacity) { + if (storage == nullptr) { + storage = new E[INITIAL_SIZE]; + _capacity = INITIAL_SIZE; + } else if (_lastIdx >= _capacity) { // Need to expand _capacity first _capacity *= 2; E* newStorage = new E[_capacity]; @@ -184,6 +193,10 @@ class Vector { } bool remove(const E& obj) { + if (storage == nullptr || isEmpty()) { + return false; + } + bool found = false; size_t newLast = _firstIdx; for (size_t i = _firstIdx; i < _lastIdx; i += 1) { @@ -199,13 +212,22 @@ class Vector { } void removeAll() { + destroyValues(); + _firstIdx = 0; _lastIdx = 0; + + if (storage != nullptr) { + delete[] storage; + storage = new E[_capacity]; + } } [[nodiscard]] size_t size() const { return _lastIdx - _firstIdx; } - [[nodiscard]] size_t getCapacity() const { return _capacity; } + [[nodiscard]] size_t getCapacity() const { + return storage == nullptr ? 0 : _capacity; + } void sort(std::function c) { if (size() > 0) { From 5eccd197520e37faface738726ca329a2c2c2357 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 11 Feb 2024 01:25:47 +0000 Subject: [PATCH 32/40] [C++] Added support for compiling with profile-guided optimizations Signed-off-by: Stefan Marr --- benchmarks/C++/build.sh | 76 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/benchmarks/C++/build.sh b/benchmarks/C++/build.sh index bc0b5794..0b266e1b 100755 --- a/benchmarks/C++/build.sh +++ b/benchmarks/C++/build.sh @@ -2,6 +2,12 @@ SCRIPT_PATH="$(dirname "$0")" source "$SCRIPT_PATH/../script.inc" +if [ -z "$OPT" ]; then + OPT='-O3 -flto -march=native' +fi +NAME_OPT="${OPT//[[:blank:]]/}" +NAME_OPT="${NAME_OPT//flto/lto}" + # start by trying to find a suitable clang CMD_VERSION='-mp-17' @@ -12,9 +18,46 @@ if ! [ -x "$(command -v clang++$CMD_VERSION)" ]; then fi fi -CMD="clang++$CMD_VERSION" +if [ -z "$CXX" ]; then + CMD="clang++$CMD_VERSION" + CXX="$CMD" + + # trying to avoid bugs, CXX should be used at this point + unset CMD +fi + +if [[ $CXX == *"clang"* ]]; then + COMPILER_NAME="clang" + WARNINGS="-Wall -Wextra -Wno-unused-private-field" +else + # we assume gcc + COMPILER_NAME="gcc" + WARNINGS="-Wall -Wextra" +fi +COMP_OPT="-ffp-contract=off -std=c++17" + +echo "Using compiler type: $COMPILER_NAME" + +SRC='src/harness.cpp src/deltablue.cpp src/memory/object_tracker.cpp src/richards.cpp' + +BENCHMARKS=("NBody 10 250000" + "Richards 10 100" + "DeltaBlue 10 1200" + "Mandelbrot 10 500" + "Queens 10 1000" + "Towers 10 600" + "Bounce 10 1500" + "CD 10 250" + "Json 10 100" + "List 10 1500" + "Storage 10 1000" + "Sieve 10 3000" + "Mandelbrot 10 500" + "Permute 10 1000" + "Bounce 10 1500" + "Mandelbrot 10 500" + "Havlak 10 1500") -pushd "$SCRIPT_PATH" if [ "$1" = "style" ] then @@ -82,13 +125,34 @@ then -Wno-sign-conversion -Wno-unsafe-buffer-usage -Wno-weak-vtables' SANATIZE="-Weverything -pedantic -Wall -Wextra $DISABLED_WARNINGS" - OPT='-O3' echo Bulding with pedantic warnings and $OPT optimizations +elif [ "$1" = "pgo" ] +then + echo Bulding with PGO optimizations + ORG_OPT="$OPT" + + OPT="$ORG_OPT -fprofile-generate" + $CXX $WARNINGS $SANATIZE $OPT $COMP_OPT $SRC -o harness-$CXX + + for b in "${BENCHMARKS[@]}"; do + LLVM_PROFILE_FILE="prof-%p.profraw" ./harness-$CXX $b + done + + if [ "$COMPILER_NAME" = "clang" ]; then + llvm-profdata$CMD_VERSION merge -output=prof.profdata prof-*.profraw + OPT="$ORG_OPT -fprofile-use=prof.profdata" + else + OPT="$ORG_OPT -fprofile-use" + fi + + $CXX $WARNINGS $SANATIZE $OPT $COMP_OPT $SRC -o harness-$CXX$NAME_OPT-pgo + EXIT_CODE=$? + rm -f *.profraw prof.profdata *.gcda + exit $EXIT_CODE else echo Bulding with $OPT optimizations SANATIZE='' fi -SRC='src/harness.cpp src/deltablue.cpp src/memory/object_tracker.cpp src/richards.cpp' - -exec $CMD -Wall -Wextra -Wno-unused-private-field $SANATIZE $OPT -ffp-contract=off -std=c++17 $SRC -o harness +echo Binary name: harness-$CXX$NAME_OPT +exec $CXX $WARNINGS $SANATIZE $OPT $COMP_OPT $SRC -o harness-$CXX$NAME_OPT From 3f3e2b26e94fa20827ce4c3c602f6f92039b18e4 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sat, 13 Jan 2024 13:48:54 +0000 Subject: [PATCH 33/40] [C++] Missing parentheses, based on G++ warning Signed-off-by: Stefan Marr --- benchmarks/C++/src/json.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/C++/src/json.h b/benchmarks/C++/src/json.h index 0eeeda13..4bc00464 100644 --- a/benchmarks/C++/src/json.h +++ b/benchmarks/C++/src/json.h @@ -478,7 +478,7 @@ class HashIndexTable { } [[nodiscard]] int32_t hashSlotFor(const std::string& element) const { - return stringHash(element) & static_cast(_hashTable.size()) - 1; + return stringHash(element) & (static_cast(_hashTable.size()) - 1); } }; From 540543f0c80e579d05f1e59ef01b7677f99179a7 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 12 Jan 2024 23:05:36 +0000 Subject: [PATCH 34/40] [C++] Fix lint Signed-off-by: Stefan Marr --- benchmarks/C++/src/json.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/C++/src/json.h b/benchmarks/C++/src/json.h index 4bc00464..ff9fbd4f 100644 --- a/benchmarks/C++/src/json.h +++ b/benchmarks/C++/src/json.h @@ -999,7 +999,7 @@ class Json : public Benchmark { } bool verify_result(std::any r) override { - auto* const result = std::any_cast(r); + const auto* const result = std::any_cast(r); const bool doesVerify = has_expected_content(result); delete result; return doesVerify; From df177fbb37538698c8470ddb26eec128d930ce02 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 12 Jan 2024 15:20:03 +0000 Subject: [PATCH 35/40] [C++] Small improvements in Towers Signed-off-by: Stefan Marr --- benchmarks/C++/src/towers.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/benchmarks/C++/src/towers.h b/benchmarks/C++/src/towers.h index a0104228..52955849 100644 --- a/benchmarks/C++/src/towers.h +++ b/benchmarks/C++/src/towers.h @@ -14,11 +14,7 @@ class TowersDisk { public: explicit TowersDisk(int32_t size) : size(size) {} - ~TowersDisk() { - if (next != nullptr) { - delete next; - } - } + ~TowersDisk() { delete next; } [[nodiscard]] int32_t get_size() const { return size; } @@ -34,7 +30,7 @@ class Towers : public Benchmark { public: std::any benchmark() override { - piles = std::array(); + piles = std::array{}; build_tower_at(0, 13); moves_done = 0; move_disks(13, 0, 1); From 05955b2683ab860d1beb85bb7e5f725672816cea Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 12 Jan 2024 15:20:34 +0000 Subject: [PATCH 36/40] [C++] Fix rule violations in Havlak Signed-off-by: Stefan Marr --- benchmarks/C++/src/havlak.h | 46 +++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/benchmarks/C++/src/havlak.h b/benchmarks/C++/src/havlak.h index b34f78b4..2fa371e3 100644 --- a/benchmarks/C++/src/havlak.h +++ b/benchmarks/C++/src/havlak.h @@ -17,8 +17,8 @@ class BasicBlock : public CustomHash { public: explicit BasicBlock(int32_t name) : _name(name) {} - Vector* getInEdges() { return &_inEdges; } - Vector* getOutEdges() { return &_outEdges; } + Vector& getInEdges() { return _inEdges; } + Vector& getOutEdges() { return _outEdges; } int32_t getNumPred() { return static_cast(_inEdges.size()); } void addOutEdge(BasicBlock* to) { _outEdges.append(to); } void addInEdge(BasicBlock* from) { _inEdges.append(from); } @@ -61,7 +61,7 @@ class ControlFlowGraph { void addEdge(BasicBlockEdge* edge) { _edgeList.append(edge); } int32_t getNumNodes() { return static_cast(_basicBlockMap.size()); } BasicBlock* getStartBasicBlock() { return _startNode; } - Vector* getBasicBlocks() { return &_basicBlockMap; } + Vector& getBasicBlocks() { return _basicBlockMap; } }; class BasicBlockEdge { @@ -74,6 +74,8 @@ class BasicBlockEdge { : _from(cfg.createNode(fromName)), _to(cfg.createNode(toName)) { _from->addOutEdge(_to); _to->addInEdge(_from); + + cfg.addEdge(this); } }; @@ -89,6 +91,8 @@ class SimpleLoop { int32_t _counter{0}; int32_t _depthLevel{0}; + void addChildLoop(SimpleLoop* loop) { _children.add(loop); } + public: SimpleLoop(BasicBlock* bb, bool isReducible) : _header(bb), _isReducible(isReducible) { @@ -100,17 +104,15 @@ class SimpleLoop { bool equal(SimpleLoop* other) const { return this == other; } void addNode(BasicBlock* bb) { _basicBlocks.add(bb); } - void addChildLoop(SimpleLoop* loop) { _children.add(loop); } - [[nodiscard]] IdentitySet* getChildren() { return &_children; } - [[nodiscard]] SimpleLoop* getParent() { return _parent; } + + [[nodiscard]] IdentitySet& getChildren() { return _children; } + [[nodiscard]] SimpleLoop* getParent() const { return _parent; } [[nodiscard]] int32_t getNestingLevel() const { return _nestingLevel; } [[nodiscard]] bool isRoot() const { return _isRoot; } void setParent(SimpleLoop* parent) { _parent = parent; - if (parent != nullptr) { - parent->addChildLoop(this); - } + _parent->addChildLoop(this); } void setIsRoot() { _isRoot = true; } @@ -166,7 +168,7 @@ class LoopStructureGraph { void calculateNestingLevelRec(SimpleLoop* loop, int32_t depth) { loop->setDepthLevel(depth); - loop->getChildren()->forEach( + loop->getChildren().forEach( [this, loop, depth](SimpleLoop* const& liter) -> void { calculateNestingLevelRec(liter, depth + 1); @@ -208,7 +210,7 @@ class UnionFindNode { // Path Compression, all nodes' parents point to the 1st level parent. nodeList.forEach( - [&](UnionFindNode* const& iter) -> void { iter->unionSet(_parent); }); + [this](UnionFindNode* const& iter) -> void { iter->unionSet(_parent); }); return node; } @@ -341,10 +343,10 @@ class HavlakLoopFinder { _number.atPut(currentNode, current); int32_t lastId = current; - Vector* outerBlocks = currentNode->getOutEdges(); + Vector& outerBlocks = currentNode->getOutEdges(); - for (int32_t i = 0; i < static_cast(outerBlocks->size()); i += 1) { - BasicBlock* target = *outerBlocks->at(i); + for (int32_t i = 0; i < static_cast(outerBlocks.size()); i += 1) { + BasicBlock* target = *outerBlocks.at(i); if (*_number.at(target) == UNVISITED) { lastId = doDFS(target, lastId + 1); } @@ -355,7 +357,7 @@ class HavlakLoopFinder { } void initAllNodes() { - _cfg.getBasicBlocks()->forEach([this](BasicBlock* const& bb) -> void { + _cfg.getBasicBlocks().forEach([this](BasicBlock* const& bb) -> void { _number.atPut(bb, UNVISITED); }); doDFS(_cfg.getStartBasicBlock(), 0); @@ -377,7 +379,7 @@ class HavlakLoopFinder { void processEdges(BasicBlock* nodeW, int32_t w) { if (nodeW->getNumPred() > 0) { - nodeW->getInEdges()->forEach([this, w](BasicBlock* const& nodeV) -> void { + nodeW->getInEdges().forEach([this, w](BasicBlock* const& nodeV) -> void { const int32_t v = *_number.at(nodeV); if (v != UNVISITED) { if (isAncestor(w, v)) { @@ -452,16 +454,16 @@ class LoopTesterApp { int32_t buildDiamond(int32_t start) { const int32_t bb0 = start; - _cfg.addEdge(new BasicBlockEdge(_cfg, bb0, bb0 + 1)); - _cfg.addEdge(new BasicBlockEdge(_cfg, bb0, bb0 + 2)); - _cfg.addEdge(new BasicBlockEdge(_cfg, bb0 + 1, bb0 + 3)); - _cfg.addEdge(new BasicBlockEdge(_cfg, bb0 + 2, bb0 + 3)); + new BasicBlockEdge(_cfg, bb0, bb0 + 1); + new BasicBlockEdge(_cfg, bb0, bb0 + 2); + new BasicBlockEdge(_cfg, bb0 + 1, bb0 + 3); + new BasicBlockEdge(_cfg, bb0 + 2, bb0 + 3); return bb0 + 3; } void buildConnect(int32_t start, int32_t end) { - _cfg.addEdge(new BasicBlockEdge(_cfg, start, end)); + new BasicBlockEdge(_cfg, start, end); } int32_t buildStraight(int32_t start, int32_t n) { @@ -489,7 +491,7 @@ class LoopTesterApp { buildBaseLoop(0); _cfg.createNode(1); - _cfg.addEdge(new BasicBlockEdge(_cfg, 0, 2)); + new BasicBlockEdge(_cfg, 0, 2); } public: From 324c4a429b5c882a8c1ff8a4bacb5b5f26a6f796 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 12 Jan 2024 23:05:09 +0000 Subject: [PATCH 37/40] [C++] Use template for dictionary key type Signed-off-by: Stefan Marr --- benchmarks/C++/src/deltablue.cpp | 15 +++---- benchmarks/C++/src/deltablue.h | 14 +++---- benchmarks/C++/src/havlak.h | 14 ++++--- benchmarks/C++/src/som/dictionary.h | 41 ++++++++------------ benchmarks/C++/src/som/identity_dictionary.h | 24 ++++++------ docs/guidelines.md | 12 +++--- 6 files changed, 59 insertions(+), 61 deletions(-) diff --git a/benchmarks/C++/src/deltablue.cpp b/benchmarks/C++/src/deltablue.cpp index bbfa6154..304c66f1 100644 --- a/benchmarks/C++/src/deltablue.cpp +++ b/benchmarks/C++/src/deltablue.cpp @@ -15,8 +15,8 @@ const Sym Strength::DEFAULT(5); const Sym Strength::WEAK_DEFAULT(6); const Sym Strength::ABSOLUTE_WEAKEST(7); -IdentityDictionary* Strength::_strengthTable; -IdentityDictionary* Strength::_strengthConstant; +IdentityDictionary* Strength::_strengthTable; +IdentityDictionary* Strength::_strengthConstant; const Strength* Strength::_absoluteWeakest; const Strength* Strength::_required; @@ -28,8 +28,8 @@ const Strength* Strength::required() { return _required; } -IdentityDictionary* Strength::createStrengthTable() { - auto* strengthTable = new IdentityDictionary(); +IdentityDictionary* Strength::createStrengthTable() { + auto* strengthTable = new IdentityDictionary(); strengthTable->atPut(&Strength::ABSOLUTE_STRONGEST, -10000); strengthTable->atPut(&Strength::REQUIRED, -800); strengthTable->atPut(&Strength::STRONG_PREFERRED, -600); @@ -41,10 +41,11 @@ IdentityDictionary* Strength::createStrengthTable() { return strengthTable; } -IdentityDictionary* Strength::createStrengthConstants() { - auto* strengthConstant = new IdentityDictionary(); +IdentityDictionary* +Strength::createStrengthConstants() { + auto* strengthConstant = new IdentityDictionary(); auto* keys = _strengthTable->getKeys(); - keys->forEach([&strengthConstant](const CustomHash* const key) -> void { + keys->forEach([&strengthConstant](const Sym* const key) -> void { const Sym* keySym = dynamic_cast(key); strengthConstant->atPut(keySym, new Strength(keySym)); }); diff --git a/benchmarks/C++/src/deltablue.h b/benchmarks/C++/src/deltablue.h index a6d5df49..feffebd8 100644 --- a/benchmarks/C++/src/deltablue.h +++ b/benchmarks/C++/src/deltablue.h @@ -10,15 +10,14 @@ enum Direction { FORWARD, BACKWARD, NONE }; -class Sym : public CustomHash { +class Sym { private: uint32_t hash; public: explicit constexpr Sym(uint32_t hash_value) noexcept : hash(hash_value) {} - ~Sym() override = default; - [[nodiscard]] uint32_t customHash() const override { return hash; } + [[nodiscard]] uint32_t customHash() const { return hash; } }; class Strength { @@ -36,8 +35,9 @@ class Strength { int32_t const _arithmeticValue; const Sym* const _symbolicValue; - static IdentityDictionary* createStrengthTable(); - static IdentityDictionary* createStrengthConstants(); + static IdentityDictionary* createStrengthTable(); + static IdentityDictionary* + createStrengthConstants(); static void releaseStrengthConstants(); public: @@ -79,8 +79,8 @@ class Strength { static const Strength* _absoluteWeakest; static const Strength* _required; - static IdentityDictionary* _strengthTable; - static IdentityDictionary* _strengthConstant; + static IdentityDictionary* _strengthTable; + static IdentityDictionary* _strengthConstant; }; class Planner; diff --git a/benchmarks/C++/src/havlak.h b/benchmarks/C++/src/havlak.h index 2fa371e3..450c5301 100644 --- a/benchmarks/C++/src/havlak.h +++ b/benchmarks/C++/src/havlak.h @@ -9,7 +9,7 @@ using std::cout; -class BasicBlock : public CustomHash { +class BasicBlock { private: Vector _inEdges{2}; Vector _outEdges{2}; @@ -17,12 +17,13 @@ class BasicBlock : public CustomHash { public: explicit BasicBlock(int32_t name) : _name(name) {} + Vector& getInEdges() { return _inEdges; } Vector& getOutEdges() { return _outEdges; } int32_t getNumPred() { return static_cast(_inEdges.size()); } void addOutEdge(BasicBlock* to) { _outEdges.append(to); } void addInEdge(BasicBlock* from) { _inEdges.append(from); } - [[nodiscard]] uint32_t customHash() const override { return _name; } + [[nodiscard]] uint32_t customHash() const { return _name; } bool equal(BasicBlock* other) const { return _name == other->_name; } }; @@ -209,8 +210,9 @@ class UnionFindNode { } // Path Compression, all nodes' parents point to the 1st level parent. - nodeList.forEach( - [this](UnionFindNode* const& iter) -> void { iter->unionSet(_parent); }); + nodeList.forEach([this](UnionFindNode* const& iter) -> void { + iter->unionSet(_parent); + }); return node; } @@ -241,7 +243,7 @@ class HavlakLoopFinder { Vector*> _nonBackPreds{}; Vector*> _backPreds{}; - IdentityDictionary _number{}; + IdentityDictionary _number{}; int32_t _maxSize{0}; int32_t* _header{nullptr}; @@ -343,7 +345,7 @@ class HavlakLoopFinder { _number.atPut(currentNode, current); int32_t lastId = current; - Vector& outerBlocks = currentNode->getOutEdges(); + const Vector& outerBlocks = currentNode->getOutEdges(); for (int32_t i = 0; i < static_cast(outerBlocks.size()); i += 1) { BasicBlock* target = *outerBlocks.at(i); diff --git a/benchmarks/C++/src/som/dictionary.h b/benchmarks/C++/src/som/dictionary.h index eaea91bd..b2c0cd56 100644 --- a/benchmarks/C++/src/som/dictionary.h +++ b/benchmarks/C++/src/som/dictionary.h @@ -3,14 +3,7 @@ #include #include "vector.h" -class CustomHash { - public: - CustomHash() = default; - virtual ~CustomHash() = default; - [[nodiscard]] virtual uint32_t customHash() const = 0; -}; - -template +template class IdentityDictionary; /** @@ -19,31 +12,31 @@ class IdentityDictionary; * The memory of Entry objects is managed by ownership through the _buckets * field. Thus, they are anchored in the _buckets, and only freed from there. */ -template +template class Dictionary { - friend class IdentityDictionary; + friend class IdentityDictionary; private: class Entry { - friend class IdentityDictionary; - friend class Dictionary; + friend class IdentityDictionary; + friend class Dictionary; private: uint32_t _hash; - const CustomHash* const _key; + const K* const _key; V _value; Entry* _next; public: - Entry(uint32_t h, const CustomHash* k, const V& v, Entry* n) + Entry(uint32_t h, const K* k, const V& v, Entry* n) : _hash(h), _key(k), _value(v), _next(n) {} virtual ~Entry() = default; - virtual bool match(uint32_t h, const CustomHash* const k) { + virtual bool match(uint32_t h, const K* const k) { return _hash == h && _key == k; } - [[nodiscard]] const CustomHash* getKey() const { return _key; } + [[nodiscard]] const K* getKey() const { return _key; } [[nodiscard]] uint32_t getHash() const { return _hash; } }; @@ -67,7 +60,7 @@ class Dictionary { [[nodiscard]] bool isEmpty() const { return _size == 0; } - [[nodiscard]] uint32_t hash(const CustomHash* key) const { + [[nodiscard]] uint32_t hash(const K* key) const { if (key == nullptr) { return 0; } @@ -75,7 +68,7 @@ class Dictionary { return h ^ (h >> 16U); } - [[nodiscard]] bool containsKey(const CustomHash* key) const { + [[nodiscard]] bool containsKey(const K* key) const { uint32_t h = hash(key); Entry* e = getBucket(h); @@ -88,7 +81,7 @@ class Dictionary { return false; } - V* at(const CustomHash* key) const { + V* at(const K* key) const { const uint32_t h = this->hash(key); Entry* e = getBucket(h); @@ -102,7 +95,7 @@ class Dictionary { return nullptr; } - void atPut(const CustomHash* const key, const V& value) { + void atPut(const K* const key, const V& value) { const uint32_t h = hash(key); const uint32_t i = getBucketIdx(h); @@ -134,8 +127,8 @@ class Dictionary { _size = 0; } - [[nodiscard]] Vector* getKeys() { - auto* keys = new Vector(); + [[nodiscard]] Vector* getKeys() { + auto* keys = new Vector(); for (uint32_t i = 0; i < _capacity; i += 1) { Entry* current = _buckets[i]; while (current != nullptr) { @@ -169,7 +162,7 @@ class Dictionary { } } - virtual Entry* newEntry(const CustomHash* key, V value, uint32_t hash) { + virtual Entry* newEntry(const K* key, V value, uint32_t hash) { return new Entry(hash, key, value, nullptr); } @@ -182,7 +175,7 @@ class Dictionary { return _buckets[getBucketIdx(hash)]; } - void insertBucketEntry(const CustomHash* key, + void insertBucketEntry(const K* key, const V& value, uint32_t hash, Entry* head) { diff --git a/benchmarks/C++/src/som/identity_dictionary.h b/benchmarks/C++/src/som/identity_dictionary.h index 6623d835..9dc17425 100644 --- a/benchmarks/C++/src/som/identity_dictionary.h +++ b/benchmarks/C++/src/som/identity_dictionary.h @@ -3,30 +3,30 @@ #include #include "dictionary.h" -template -class IdentityDictionary : public Dictionary { +template +class IdentityDictionary : public Dictionary { private: - class IdEntry : public Dictionary::Entry { + class IdEntry : public Dictionary::Entry { public: IdEntry(uint32_t hash, - const CustomHash* key, + const K* key, const V& value, - typename Dictionary::Entry* next) - : Dictionary::Entry(hash, key, value, next) {} + typename Dictionary::Entry* next) + : Dictionary::Entry(hash, key, value, next) {} ~IdEntry() override = default; - bool match(uint32_t h, const CustomHash* k) override { + bool match(uint32_t h, const K* k) override { return this->getHash() == h && this->getKey() == k; } }; public: - explicit IdentityDictionary(const uint32_t size) : Dictionary(size) {} - IdentityDictionary() : Dictionary(Dictionary::INITIAL_CAPACITY) {} + explicit IdentityDictionary(const uint32_t size) : Dictionary(size) {} + IdentityDictionary() : Dictionary(Dictionary::INITIAL_CAPACITY) {} - typename Dictionary::Entry* newEntry(const CustomHash* key, - V value, - uint32_t hash) override { + typename Dictionary::Entry* newEntry(const K* key, + V value, + uint32_t hash) override { return new IdEntry(hash, key, value, nullptr); } }; diff --git a/docs/guidelines.md b/docs/guidelines.md index 70606b73..983bc46a 100644 --- a/docs/guidelines.md +++ b/docs/guidelines.md @@ -143,7 +143,7 @@ languages. ### Python - Use plain fields instead of getter/setter when they would be trivial - + ### C++ @@ -184,7 +184,7 @@ Memory Management Strategies Per Benchmarks: - **DeltaBlue** uses `object_tracker`, since there are cyclic dependencies, but we can free the full setup once it's not needed. A mix of `shared_ptr` and `weak_ptr` would probably also work. - + - **Havlak** manages memory explicitly by assigning ownership to specific classes. Specifically, the ControlFlowGraph owns the basic blocks and block edges, the LoopStructureGraph owns the loops, the HavlakLoopFinder @@ -202,11 +202,11 @@ Memory Management Strategies Per Benchmarks: but I might have missed something. - **Bounce** allocates everything statically, i.e., on the stack. - + - **List** trivially uses the list structure for freeing the list. - + - **Mandelbrot** does not allocate any data structures. - + - **NBody** allocates everything statically, i.e., on the stack. - **Permute** allocates an array dynamically, and frees it directly. @@ -250,6 +250,8 @@ General C++-isms: - avoid changing signatures for the sake of the compiler. It should do an appropriate return-value optimization itself. + - use templates where Java uses generics + ## Repository Structure From b8bb2c8b14839c21b05b9c07d3f387ade9f29c1a Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 11 Feb 2024 11:22:13 +0000 Subject: [PATCH 38/40] [C++] Add .gitignore Signed-off-by: Stefan Marr --- benchmarks/C++/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 benchmarks/C++/.gitignore diff --git a/benchmarks/C++/.gitignore b/benchmarks/C++/.gitignore new file mode 100644 index 00000000..eca8fb02 --- /dev/null +++ b/benchmarks/C++/.gitignore @@ -0,0 +1,2 @@ +.vscode +/harness* From 1fda5018a7a600eb9ec1090470cb9ae32986364b Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Sun, 11 Feb 2024 18:43:36 +0000 Subject: [PATCH 39/40] [C++] Create a symlink to make testing with test.conf easier Signed-off-by: Stefan Marr --- benchmarks/C++/build.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/benchmarks/C++/build.sh b/benchmarks/C++/build.sh index 0b266e1b..fde78e37 100755 --- a/benchmarks/C++/build.sh +++ b/benchmarks/C++/build.sh @@ -58,6 +58,7 @@ BENCHMARKS=("NBody 10 250000" "Mandelbrot 10 500" "Havlak 10 1500") +pushd "$SCRIPT_PATH" if [ "$1" = "style" ] then @@ -155,4 +156,5 @@ else fi echo Binary name: harness-$CXX$NAME_OPT -exec $CXX $WARNINGS $SANATIZE $OPT $COMP_OPT $SRC -o harness-$CXX$NAME_OPT +eval $CXX $WARNINGS $SANATIZE $OPT $COMP_OPT $SRC -o harness-$CXX$NAME_OPT +ln -sf harness-$CXX$NAME_OPT harness From c55b00e2d4605a45fb63e56d55af503ad07dbf85 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 16 Feb 2024 21:32:03 +0000 Subject: [PATCH 40/40] [C++] Edit guidelines Signed-off-by: Stefan Marr --- docs/guidelines.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/guidelines.md b/docs/guidelines.md index 983bc46a..9f3a2bfd 100644 --- a/docs/guidelines.md +++ b/docs/guidelines.md @@ -71,7 +71,7 @@ requirements of the benchmarks. As a basic guideline, we use the following rules: - - Code should pass a linter (if available). This gives some basic consistency + - Code should pass a linter, if available, to ensure some basic consistency with established rules. However, some language-specific rules impact comparability for an example see our [Ruby Rubocop](../benchmarks/Ruby/.rubocop.yml) settings. @@ -85,7 +85,7 @@ As a basic guideline, we use the following rules: properties preferable. - Identical code structure is more important than 100% idiomatic code. - While prefer the use of idiomatic iteration constructs, in other cases it is + While we prefer idiomatic iteration constructs, in other cases it is required to use the same structure of methods and similar naming to prevent differences in the general code structure etc. @@ -147,7 +147,7 @@ languages. ### C++ -With C++, we add support for the first language that does not have garbage +With C++, we added support for the first language that does not have garbage collection, which comes with a new dimension of issues to be considered. Explicit Memory Management Rules: @@ -170,9 +170,9 @@ Explicit Memory Management Rules: the allocations referenced by these fields should be freed before the end of a method, but the field should remain a field. - - for arbitrary object graphs, as in DeltaBlue, memory/object_tracker.h can + - for arbitrary object graphs, as in DeltaBlue, `memory/object_tracker.h` can be used to free the objects when not needed. - The use of shared_ptr may also be appropriate, but did not work for DeltaBlue. + The use of `shared_ptr` may also be appropriate, but did not work for DeltaBlue. Memory Management Strategies Per Benchmarks: @@ -183,7 +183,7 @@ Memory Management Strategies Per Benchmarks: - **DeltaBlue** uses `object_tracker`, since there are cyclic dependencies, but we can free the full setup once it's not needed. - A mix of `shared_ptr` and `weak_ptr` would probably also work. + A mix of `shared_ptr` and `weak_ptr` could probably also work. - **Havlak** manages memory explicitly by assigning ownership to specific classes. Specifically, the ControlFlowGraph owns the basic blocks and @@ -197,8 +197,8 @@ Memory Management Strategies Per Benchmarks: Though, otherwise, we do not require any management overhead. - **Richards** uses `object_tracker` for simplicity. - It could use `shared_ptr` and accounting for cyclic references that would - work, too. A naive using of the task list did not seem to work, + It could use `shared_ptr` and when accounting for cyclic references that + could work, too. Naively freing the task list did not seem to work, but I might have missed something. - **Bounce** allocates everything statically, i.e., on the stack. @@ -211,7 +211,7 @@ Memory Management Strategies Per Benchmarks: - **Permute** allocates an array dynamically, and frees it directly. Since the benchmark holds the reference in a field, and allocates on - each iteration, the new/delete dance is needed to comply + each iteration, the new/delete dance is needed to comply. - **Queens** allocates its arrays dynamically, and frees them directly, same as Permute. @@ -230,7 +230,7 @@ General C++-isms: - we use clang-tidy and clang-format - - use std::array for fixed-sized arrays + - use `std::array` for fixed-sized arrays - use `const` where it is appropriate, but it won't really work with containers and can be problematic for value classes @@ -238,9 +238,9 @@ General C++-isms: - use `auto` and `auto*` to make code more concise as recommended by linter, for instance for allocations - - use annotations like [[nodiscard]] where indicated by the linter + - use annotations like `[[nodiscard]]` where indicated by the linter - - use modern C++-isms, for instance range loops and .at instead of [] on std::array + - use modern C++-isms, for instance range loops and `.at()` instead of `[]` on `std::array` - use initializer syntax for default values and member initializers lists when depending on constructor parameter