|
| 1 | +#include <bench.hpp> |
| 2 | +#include <boost/json.hpp> |
| 3 | +#include <boost/json/src.hpp> |
| 4 | +#include <cstdio> |
| 5 | +#include <faker-cxx/location.h> |
| 6 | +#include <faker-cxx/number.h> |
| 7 | +#include <filesystem> |
| 8 | +#include <fstream> |
| 9 | +#include <iostream> |
| 10 | +#include <jsonlogic/logic.hpp> |
| 11 | +#include <string> |
| 12 | +#include <vector> |
| 13 | + |
| 14 | +std::string read_file(const std::string &filename) { |
| 15 | + std::ifstream file(filename); |
| 16 | + if (!file) |
| 17 | + throw std::runtime_error("Failed to open file"); |
| 18 | + |
| 19 | + return {std::string((std::istreambuf_iterator<char>(file)), |
| 20 | + std::istreambuf_iterator<char>())}; |
| 21 | +} |
| 22 | + |
| 23 | +const unsigned long SEED_ = 42; |
| 24 | +static const size_t N_ = 1'000'000; |
| 25 | +static const int N_RUNS_ = 3; |
| 26 | + |
| 27 | +int main(int argc, const char **argv) try { |
| 28 | + |
| 29 | + // Test expression: x > 5 and y < 3 |
| 30 | + std::string expr; |
| 31 | + try { |
| 32 | + expr = read_file("simple-and.json"); |
| 33 | + std::cout << "Successfully read simple-and.json from current directory" |
| 34 | + << std::endl; |
| 35 | + } catch (const std::exception &) { |
| 36 | + try { |
| 37 | + expr = read_file("bench/src/simple-and.json"); |
| 38 | + std::cout << "Successfully read simple-and.json from bench/src/" |
| 39 | + << std::endl; |
| 40 | + } catch (const std::exception &e) { |
| 41 | + std::cerr << "Error: Could not find simple-and.json: " << e.what() |
| 42 | + << std::endl; |
| 43 | + // Print current working directory |
| 44 | + std::cerr << "Current directory: " << std::filesystem::current_path() |
| 45 | + << std::endl; |
| 46 | + throw; |
| 47 | + } |
| 48 | + } |
| 49 | + |
| 50 | + std::span<const char *> args(argv, argc); |
| 51 | + |
| 52 | + size_t N = N_; |
| 53 | + if (argc > 1) { |
| 54 | + N = std::stoul(args[1]); |
| 55 | + } |
| 56 | + size_t N_RUNS = N_RUNS_; |
| 57 | + if (argc > 2) { |
| 58 | + N_RUNS = std::stoul(args[2]); |
| 59 | + } |
| 60 | + |
| 61 | + size_t SEED = SEED_; |
| 62 | + if (argc > 3) { |
| 63 | + SEED = std::stoul(args[3]); |
| 64 | + } |
| 65 | + |
| 66 | + faker::getGenerator().seed(SEED); |
| 67 | + std::vector<double> xs; |
| 68 | + xs.reserve(N); |
| 69 | + std::vector<int> ys; |
| 70 | + ys.reserve(N); |
| 71 | + |
| 72 | + // Create test data |
| 73 | + for (size_t i = 0; i < N; ++i) { |
| 74 | + xs.push_back(faker::number::decimal<double>( |
| 75 | + 0, 10)); // 0-10 range to get some matches |
| 76 | + ys.push_back( |
| 77 | + faker::number::integer<int>(0, 6)); // 0-6 range to get some matches |
| 78 | + } |
| 79 | + |
| 80 | + // JL1 - Using boost::json::object approach |
| 81 | + |
| 82 | + auto jv_expr = boost::json::parse(expr); |
| 83 | + boost::json::object data_obj; |
| 84 | + |
| 85 | + size_t matches = 0; |
| 86 | + auto jl1_lambda = [&] { |
| 87 | + matches = 0; |
| 88 | + for (size_t i = 0; i < N; ++i) { |
| 89 | + data_obj["x"] = xs[i]; |
| 90 | + data_obj["y"] = ys[i]; |
| 91 | + auto data = boost::json::value_from(data_obj); |
| 92 | + auto result = jsonlogic::apply(jv_expr, data); |
| 93 | + |
| 94 | + bool val = jsonlogic::truthy(result); |
| 95 | + |
| 96 | + if (val) { |
| 97 | + ++matches; |
| 98 | + } |
| 99 | + } |
| 100 | + }; |
| 101 | + |
| 102 | + auto jl1_bench = Benchmark("simple-and-jl1", jl1_lambda); |
| 103 | + |
| 104 | + // JL2 - Using create_logic approach |
| 105 | + |
| 106 | + auto jl2_lambda = [&] { |
| 107 | + matches = 0; |
| 108 | + auto [rule, ignore1, ignore2] = jsonlogic::create_logic(jv_expr); |
| 109 | + for (size_t i = 0; i < N; ++i) { |
| 110 | + auto result = jsonlogic::apply(rule, {xs[i], ys[i]}); |
| 111 | + bool val = jsonlogic::truthy(result); |
| 112 | + |
| 113 | + if (val) { |
| 114 | + ++matches; |
| 115 | + } |
| 116 | + } |
| 117 | + }; |
| 118 | + |
| 119 | + auto jl2_bench = Benchmark("simple-and-jl2", jl2_lambda); |
| 120 | + |
| 121 | + // Run benchmarks |
| 122 | + auto jl1_results = jl1_bench.run(N_RUNS); |
| 123 | + std::cout << "JL1 matches: " << matches << std::endl; |
| 124 | + |
| 125 | + auto jl2_results = jl2_bench.run(N_RUNS); |
| 126 | + std::cout << "JL2 matches: " << matches << std::endl; |
| 127 | + |
| 128 | + // Display results |
| 129 | + jl1_results.summarize(); |
| 130 | + jl2_results.summarize(); |
| 131 | + jl2_results.compare_to(jl1_results); |
| 132 | + |
| 133 | + return 0; |
| 134 | +} catch (const std::exception &e) { |
| 135 | + std::cerr << "Fatal error: " << e.what() << '\n'; |
| 136 | + return 1; |
| 137 | +} catch (...) { |
| 138 | + std::cerr << "Fatal unknown error\n"; |
| 139 | + return 2; |
| 140 | +} |
0 commit comments