Line data Source code
1 : #include "cli_args.h"
2 :
3 : #include <algorithm>
4 : #include <cctype>
5 : #include <unordered_set>
6 :
7 : namespace hashbrowns {
8 : namespace cli {
9 :
10 2 : CliArgs parse_args(int argc, char* argv[]) {
11 2 : CliArgs a;
12 4 : static const std::unordered_set<std::string> kValidProfiles = {"smoke", "ci", "series", "crossover", "deep"};
13 :
14 : // --- Pre-scan for early-exit flags ---
15 12 : for (int i = 1; i < argc; ++i) {
16 30 : std::string arg = argv[i];
17 10 : if (arg == "--no-banner")
18 0 : a.no_banner = true;
19 10 : if (arg == "--quiet") {
20 0 : a.quiet = true;
21 0 : a.no_banner = true;
22 : }
23 10 : if (arg == "--version") {
24 0 : a.version_only = true;
25 0 : a.no_banner = true;
26 : }
27 10 : }
28 :
29 2 : if (a.version_only)
30 0 : return a;
31 :
32 : // --- Full parse ---
33 7 : for (int i = 1; i < argc; ++i) {
34 15 : std::string arg = argv[i];
35 :
36 5 : if (arg == "--help" || arg == "-h") {
37 0 : a.show_help = true;
38 0 : a.demo_mode = false;
39 5 : } else if (arg == "--version") {
40 0 : a.demo_mode = false;
41 5 : } else if (arg == "--wizard" || arg == "-wizard") {
42 0 : a.wizard_mode = true;
43 0 : a.demo_mode = false;
44 5 : } else if (arg == "--size" && i + 1 < argc) {
45 3 : a.opt_size = static_cast<std::size_t>(std::stoull(argv[++i]));
46 1 : a.opt_size_explicit = true;
47 1 : a.demo_mode = false;
48 4 : } else if (arg == "--runs" && i + 1 < argc) {
49 3 : a.opt_runs = std::stoi(argv[++i]);
50 1 : a.opt_runs_explicit = true;
51 1 : a.demo_mode = false;
52 3 : } else if (arg == "--warmup" && i + 1 < argc) {
53 0 : a.opt_warmup = std::stoi(argv[++i]);
54 0 : a.opt_warmup_explicit = true;
55 0 : a.demo_mode = false;
56 3 : } else if (arg == "--bootstrap" && i + 1 < argc) {
57 0 : a.opt_bootstrap = std::stoi(argv[++i]);
58 0 : a.opt_bootstrap_explicit = true;
59 0 : a.demo_mode = false;
60 3 : } else if (arg == "--series-count" && i + 1 < argc) {
61 0 : a.opt_series_count = std::stoi(argv[++i]);
62 0 : a.opt_series_count_explicit = true;
63 0 : a.demo_mode = false;
64 3 : } else if (arg == "--series-out" && i + 1 < argc) {
65 0 : a.opt_series_out = std::string(argv[++i]);
66 0 : a.opt_series_out_explicit = true;
67 0 : a.demo_mode = false;
68 3 : } else if (arg == "--series-sizes" && i + 1 < argc) {
69 0 : std::string list = argv[++i];
70 0 : std::size_t start = 0, pos = 0;
71 0 : while ((pos = list.find(',', start)) != std::string::npos) {
72 0 : auto tok = list.substr(start, pos - start);
73 0 : if (!tok.empty())
74 0 : a.opt_series_sizes.push_back(static_cast<std::size_t>(std::stoull(tok)));
75 0 : start = pos + 1;
76 0 : }
77 0 : if (start < list.size())
78 0 : a.opt_series_sizes.push_back(static_cast<std::size_t>(std::stoull(list.substr(start))));
79 0 : a.opt_series_sizes_explicit = true;
80 0 : a.demo_mode = false;
81 3 : } else if (arg == "--series-runs" && i + 1 < argc) {
82 0 : a.opt_series_runs = std::stoi(argv[++i]);
83 0 : a.opt_series_runs_explicit = true;
84 0 : a.demo_mode = false;
85 3 : } else if (arg == "--structures" && i + 1 < argc) {
86 0 : std::string list = argv[++i];
87 0 : std::size_t start = 0, pos = 0;
88 0 : while ((pos = list.find(',', start)) != std::string::npos) {
89 0 : a.opt_structures.push_back(list.substr(start, pos - start));
90 0 : start = pos + 1;
91 : }
92 0 : if (start < list.size())
93 0 : a.opt_structures.push_back(list.substr(start));
94 0 : a.opt_structures_explicit = true;
95 0 : a.demo_mode = false;
96 3 : } else if (arg == "--output" && i + 1 < argc) {
97 0 : a.opt_output = std::string(argv[++i]);
98 0 : a.opt_output_explicit = true;
99 0 : a.demo_mode = false;
100 3 : } else if (arg == "--profile" && i + 1 < argc) {
101 6 : std::string profile = argv[++i];
102 2 : std::transform(profile.begin(), profile.end(), profile.begin(), [](unsigned char c) {
103 4 : return static_cast<char>(std::tolower(c));
104 : });
105 2 : a.opt_profile = profile;
106 2 : a.opt_profile_valid = (kValidProfiles.find(profile) != kValidProfiles.end());
107 2 : a.demo_mode = false;
108 3 : } else if (arg == "--memory-tracking") {
109 0 : a.opt_memory_tracking = true;
110 0 : a.opt_memory_tracking_explicit = true;
111 0 : a.demo_mode = false;
112 1 : } else if (arg == "--crossover-analysis") {
113 0 : a.opt_crossover = true;
114 0 : a.opt_crossover_explicit = true;
115 0 : a.demo_mode = false;
116 1 : } else if (arg == "--max-size" && i + 1 < argc) {
117 0 : a.opt_max_size = static_cast<std::size_t>(std::stoull(argv[++i]));
118 0 : a.opt_max_size_explicit = true;
119 0 : a.demo_mode = false;
120 1 : } else if (arg == "--pattern" && i + 1 < argc) {
121 0 : std::string p = argv[++i];
122 0 : if (p == "sequential")
123 0 : a.opt_pattern = BenchmarkConfig::Pattern::SEQUENTIAL;
124 0 : else if (p == "random")
125 0 : a.opt_pattern = BenchmarkConfig::Pattern::RANDOM;
126 0 : else if (p == "mixed")
127 0 : a.opt_pattern = BenchmarkConfig::Pattern::MIXED;
128 0 : a.opt_pattern_explicit = true;
129 0 : a.demo_mode = false;
130 1 : } else if (arg == "--seed" && i + 1 < argc) {
131 0 : a.opt_seed = static_cast<unsigned long long>(std::stoull(argv[++i]));
132 0 : a.opt_seed_explicit = true;
133 0 : a.demo_mode = false;
134 1 : } else if (arg == "--pin-cpu") {
135 0 : a.opt_pin_cpu = true;
136 0 : a.opt_pin_cpu_explicit = true;
137 0 : if (i + 1 < argc) {
138 0 : std::string maybe = argv[i + 1];
139 0 : if (!maybe.empty() && std::all_of(maybe.begin(), maybe.end(), ::isdigit)) {
140 0 : ++i;
141 0 : a.opt_cpu_index = std::stoi(maybe);
142 0 : a.opt_cpu_index_explicit = true;
143 : }
144 0 : }
145 0 : a.demo_mode = false;
146 1 : } else if (arg == "--no-turbo") {
147 0 : a.opt_no_turbo = true;
148 0 : a.opt_no_turbo_explicit = true;
149 0 : a.demo_mode = false;
150 1 : } else if (arg == "--max-seconds" && i + 1 < argc) {
151 0 : a.opt_max_seconds = std::stod(argv[++i]);
152 0 : a.opt_max_seconds_explicit = true;
153 0 : a.demo_mode = false;
154 1 : } else if (arg == "--out-format" && i + 1 < argc) {
155 3 : std::string f = argv[++i];
156 1 : a.opt_out_fmt = (f == "json") ? BenchmarkConfig::OutputFormat::JSON : BenchmarkConfig::OutputFormat::CSV;
157 1 : a.opt_out_format_explicit = true;
158 1 : a.demo_mode = false;
159 1 : } else if (arg == "--hash-strategy" && i + 1 < argc) {
160 0 : std::string s = argv[++i];
161 0 : if (s == "open")
162 0 : a.opt_hash_strategy = HashStrategy::OPEN_ADDRESSING;
163 0 : else if (s == "chain")
164 0 : a.opt_hash_strategy = HashStrategy::SEPARATE_CHAINING;
165 0 : a.opt_hash_strategy_explicit = true;
166 0 : a.demo_mode = false;
167 0 : } else if (arg == "--hash-capacity" && i + 1 < argc) {
168 0 : a.opt_hash_capacity = static_cast<std::size_t>(std::stoull(argv[++i]));
169 0 : a.opt_hash_capacity_explicit = true;
170 0 : a.demo_mode = false;
171 0 : } else if (arg == "--hash-load" && i + 1 < argc) {
172 0 : a.opt_hash_load = std::stod(argv[++i]);
173 0 : a.opt_hash_load_explicit = true;
174 0 : a.demo_mode = false;
175 0 : } else if (arg == "--baseline" && i + 1 < argc) {
176 0 : a.opt_baseline_path = std::string(argv[++i]);
177 0 : a.demo_mode = false;
178 0 : } else if (arg == "--baseline-report-json" && i + 1 < argc) {
179 0 : a.opt_baseline_report_json = std::string(argv[++i]);
180 0 : a.demo_mode = false;
181 0 : } else if (arg == "--baseline-threshold" && i + 1 < argc) {
182 0 : a.opt_baseline_threshold = std::stod(argv[++i]);
183 0 : a.demo_mode = false;
184 0 : } else if (arg == "--baseline-noise" && i + 1 < argc) {
185 0 : a.opt_baseline_noise = std::stod(argv[++i]);
186 0 : a.demo_mode = false;
187 0 : } else if (arg == "--baseline-scope" && i + 1 < argc) {
188 0 : std::string s = argv[++i];
189 0 : if (s == "mean")
190 0 : a.opt_baseline_scope = BaselineConfig::MetricScope::MEAN;
191 0 : else if (s == "p95")
192 0 : a.opt_baseline_scope = BaselineConfig::MetricScope::P95;
193 0 : else if (s == "ci_high")
194 0 : a.opt_baseline_scope = BaselineConfig::MetricScope::CI_HIGH;
195 0 : else if (s == "any")
196 0 : a.opt_baseline_scope = BaselineConfig::MetricScope::ANY;
197 0 : a.demo_mode = false;
198 0 : } else if (arg == "--baseline-strict-profile-intent") {
199 0 : a.opt_baseline_strict_profile_intent = true;
200 0 : a.demo_mode = false;
201 0 : } else if (arg == "--op-tests") {
202 0 : a.opt_op_tests = true;
203 0 : a.demo_mode = false;
204 0 : } else if (arg == "--no-banner" || arg == "--quiet") {
205 0 : a.demo_mode = false;
206 0 : } else if (arg.rfind("--", 0) == 0) {
207 0 : a.demo_mode = false;
208 : }
209 5 : }
210 :
211 2 : return a;
212 0 : }
213 :
214 : } // namespace cli
215 : } // namespace hashbrowns
|