| 12 | // 32MB blocks |
| 13 | constexpr static size_t BLOCK_SIZE = 32 * 1024 * 1024; |
| 14 | std::optional<uint64_t> HashFile(const fextl::string& Filepath) { |
| 15 | int fd = open(Filepath.c_str(), O_RDONLY); |
| 16 | if (fd == -1) { |
| 17 | return std::nullopt; |
| 18 | } |
| 19 | |
| 20 | XXH3_state_t* State {}; |
| 21 | auto HadError = [fd, &State]() { |
| 22 | close(fd); |
| 23 | if (State) { |
| 24 | XXH3_freeState(State); |
| 25 | } |
| 26 | return std::nullopt; |
| 27 | }; |
| 28 | // Get file size |
| 29 | off_t Size = lseek(fd, 0, SEEK_END); |
| 30 | if (Size == -1) { |
| 31 | return HadError(); |
| 32 | } |
| 33 | |
| 34 | // Reset to beginning |
| 35 | if (lseek(fd, 0, SEEK_SET) == -1) { |
| 36 | return HadError(); |
| 37 | } |
| 38 | |
| 39 | // Set up XXHash state |
| 40 | State = XXH3_createState(); |
| 41 | const XXH64_hash_t Seed = 0; |
| 42 | |
| 43 | if (!State) { |
| 44 | return HadError(); |
| 45 | } |
| 46 | |
| 47 | if (XXH3_64bits_reset_withSeed(State, Seed) == XXH_ERROR) { |
| 48 | return HadError(); |
| 49 | } |
| 50 | |
| 51 | const double SizeD = Size; |
| 52 | std::vector<char> Data(BLOCK_SIZE); |
| 53 | off_t CurrentOffset = 0; |
| 54 | auto Now = std::chrono::high_resolution_clock::now(); |
| 55 | |
| 56 | // Let the kernel know that we will be reading linearly |
| 57 | posix_fadvise(fd, 0, Size, POSIX_FADV_SEQUENTIAL); |
| 58 | while (CurrentOffset < Size) { |
| 59 | |
| 60 | ssize_t Result = pread(fd, Data.data(), BLOCK_SIZE, CurrentOffset); |
| 61 | if (Result == -1) { |
| 62 | return HadError(); |
| 63 | } |
| 64 | |
| 65 | if (XXH3_64bits_update(State, Data.data(), Result) == XXH_ERROR) { |
| 66 | return HadError(); |
| 67 | } |
| 68 | auto Cur = std::chrono::high_resolution_clock::now(); |
| 69 | auto Dur = Cur - Now; |
| 70 | if (Dur >= std::chrono::seconds(1)) { |
| 71 | fmt::print("{:.2}% hashed\n", (double)CurrentOffset / SizeD * 100.0); |
no test coverage detected