#include #include #include #include #include #include #include #include #include #include using elem_t = std::uint64_t; const elem_t N_ELEMENTS = 10000000; #define LOOPS 10 template struct strategy { virtual std::string name() const = 0; virtual T elements() = 0; template void run(C &&s) { using namespace std; cout << "\nBenchmarking:\t\t" << name() << '\n'; auto start = chrono::steady_clock::now(); for (auto x : elements()) { s.insert(x); } auto after_insertion = chrono::steady_clock::now(); auto insertion_time = chrono::duration_cast(after_insertion - start); cout << "Insertion phase:\t" << insertion_time << "\n"; start = chrono::steady_clock::now(); for (int i = 0; i < LOOPS; ++i) { for (auto x : elements()) { assert(s.contains(x)); } } auto after_lookups = chrono::steady_clock::now(); auto lookup_time = chrono::duration_cast(after_lookups - start); cout << "Lookup phase:\t\t" << lookup_time << "\n"; } virtual ~strategy() = default; }; using iota_t = decltype(std::views::iota(static_cast(0), static_cast(0))); struct ascending_ordered_sequence : public strategy { std::string name() const override { return "ordered sequence (ascending)"; } iota_t elements() override { return std::views::iota(static_cast(0), N_ELEMENTS); } }; static elem_t reverse(elem_t x) { return static_cast(N_ELEMENTS) - x; } using reversed_iota_t = decltype(std::views::iota(static_cast(0), static_cast(0)) | std::views::transform(reverse)); struct descending_ordered_sequence : public strategy { std::string name() const override { return "ordered sequence (descending)"; } reversed_iota_t elements() override { return std::views::iota(static_cast(1), N_ELEMENTS + 1) | std::views::transform(reverse); } }; static elem_t attack(elem_t x) { return x << (5 + std::bit_width(x)); } using attacked_iota_t = decltype(std::views::iota(static_cast(0), static_cast(0)) | std::views::transform(attack)); struct progressive_ascending_attack : public strategy { std::string name() const override { return "progressive sequence that self-heals on resize"; } attacked_iota_t elements() override { return std::views::iota(static_cast(0), N_ELEMENTS) | std::views::transform(attack); } }; using reversed_attacked_iota_t = decltype(std::views::iota(static_cast(0), static_cast(0)) | std::views::transform(reverse) | std::views::transform(attack)); struct progressive_descending_attack : public strategy { std::string name() const override { return "progressive sequence that self-heals in the end"; } reversed_attacked_iota_t elements() override { return std::views::iota(static_cast(1), N_ELEMENTS + 1) | std::views::transform(reverse) | std::views::transform(attack); } }; static elem_t shift(elem_t x) { return x << 32; } using shifted_iota_t = decltype(std::views::iota(static_cast(0), static_cast(0)) | std::views::transform(shift)); struct hard_attack : public strategy { std::string name() const override { return "carefully chosen numbers"; } shifted_iota_t elements() override { return std::views::iota(static_cast(0), N_ELEMENTS) | std::views::transform(shift); } }; template void run_all(const std::string ¬e) { std::cout << "\n«" << note << "»\n"; ascending_ordered_sequence{}.run(C{}); descending_ordered_sequence{}.run(C{}); progressive_ascending_attack{}.run(C{}); progressive_descending_attack{}.run(C{}); hard_attack{}.run(C{}); } int main() { run_all>("hash table"); run_all>("red-black tree"); return 0; }