parse a:b,c:d,... into a sorted, non-overlapping range list
| 335 | |
| 336 | // parse a:b,c:d,... into a sorted, non-overlapping range list |
| 337 | std::vector<mkpivm::ByteRange> parse_ranges(const std::string& spec) { |
| 338 | std::vector<mkpivm::ByteRange> out; |
| 339 | |
| 340 | std::size_t i = 0; |
| 341 | while (i < spec.size()) { |
| 342 | std::size_t comma = spec.find(',', i); |
| 343 | const std::string tok = spec.substr(i, comma - i); |
| 344 | const std::size_t colon = tok.find(':'); |
| 345 | if (colon == std::string::npos) throw mkpivm::Error("--ranges entry missing ':' separator: " + tok); |
| 346 | |
| 347 | const std::uint64_t a = parse_u64(tok.substr(0, colon).c_str()); |
| 348 | const std::uint64_t b = parse_u64(tok.substr(colon + 1).c_str()); |
| 349 | if (a >= b) throw mkpivm::Error("--ranges: start>=end in " + tok); |
| 350 | |
| 351 | if (b > 0xFFFFFFFFull) throw mkpivm::Error("--ranges: end > 4G in " + tok); |
| 352 | out.emplace_back(static_cast<std::uint32_t>(a), static_cast<std::uint32_t>(b)); |
| 353 | |
| 354 | if (comma == std::string::npos) break; |
| 355 | i = comma + 1; |
| 356 | } |
| 357 | |
| 358 | std::sort(out.begin(), out.end()); |
| 359 | for (std::size_t k = 1; k < out.size(); ++k) { |
| 360 | if (out[k].first < out[k - 1].second) { |
| 361 | throw mkpivm::Error( |
| 362 | "--ranges: ranges overlap: " + |
| 363 | std::to_string(out[k - 1].first) + ":" + |
| 364 | std::to_string(out[k - 1].second) + " and " + |
| 365 | std::to_string(out[k].first) + ":" + |
| 366 | std::to_string(out[k].second) |
| 367 | ); |
| 368 | } |
| 369 | } |
| 370 | |
| 371 | return out; |
| 372 | } |
| 373 | |
| 374 | // --scan: build the cfg and dump every call-target function that's eligible |
| 375 | // for --ranges virtualization |