1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
#include <variant>
#include <llfio.hpp>
#include "blake3.h"
#include "blake3_impl.h"
namespace llfio = LLFIO_V2_NAMESPACE;
template <class... Ts> struct overloads : Ts... {
using Ts::operator()...;
};
// NOTE: deduction guide only needed for Apple Clang now.
template <class... Ts> overloads(Ts...) -> overloads<Ts...>;
INLINE auto copy_wide(blake3_hasher *self, llfio::file_handle &file) noexcept
-> llfio::result<std::uint64_t> {
std::array<std::byte, 65536> buffer{};
std::uint64_t total = 0;
while (true) {
auto result = llfio::read(file, total, {buffer});
// Errors other than "interrupted" are immediately forwarded to caller.
if (result.has_error() && result.error() != llfio::errc::interrupted) {
return std::move(result).as_failure();
}
if (result.has_value()) {
auto bytes_read = result.value();
blake3_hasher_update(self, buffer.data(), bytes_read);
total += bytes_read;
if (bytes_read == 0) {
break;
}
}
}
return total;
}
INLINE auto maybe_mmap_file(llfio::file_handle &&file) noexcept
-> llfio::result<std::variant<
std::pair<llfio::mapped_file_handle, llfio::file_handle::extent_type>,
llfio::file_handle>> {
OUTCOME_TRY(auto file_size, file.maximum_extent());
if (!file.is_regular()) {
// Not a real file.
return file;
} else if (file_size < 16 * 1024) {
// Mapping small files is not worth it, and some special files that can't be
// mapped report a size of zero.
return file;
} else {
auto &&map = llfio::mapped_file_handle(
std::move(file), // transfer ownership
0, // reserve maximum extent
llfio::section_handle::flag::read, // map as read-only
0 // map from the start
);
return std::pair{std::move(map), file_size};
}
}
INLINE void blake3_hasher_update_mmap_base(blake3_hasher *self,
char const *path,
bool use_tbb) noexcept {
auto result = [=]() -> llfio::result<void> {
OUTCOME_TRY(auto file, llfio::file({}, path));
OUTCOME_TRY(auto mmap, maybe_mmap_file(std::move(file)));
OUTCOME_TRY(
std::visit(overloads{
[=](std::pair<llfio::mapped_file_handle,
llfio::file_handle::extent_type> &pair)
-> llfio::result<void> {
blake3_hasher_update_base(self, pair.first.address(),
pair.second, use_tbb);
return llfio::success();
},
[=](llfio::file_handle &file) -> llfio::result<void> {
OUTCOME_TRY(copy_wide(self, file));
return llfio::success();
},
},
mmap));
return llfio::success();
}();
if (result.has_error()) {
// Explicitly set errno on error since this doesn't always happen
// automatically on some platforms such as Windows.
errno = static_cast<int>(result.error().value().sc);
}
}
extern "C" void blake3_hasher_update_mmap(blake3_hasher *self,
char const *path) noexcept {
bool use_tbb = false;
blake3_hasher_update_mmap_base(self, path, use_tbb);
}
#if defined(BLAKE3_USE_TBB)
extern "C" void blake3_hasher_update_mmap_tbb(blake3_hasher *self,
char const *path) noexcept {
bool use_tbb = true;
blake3_hasher_update_mmap_base(self, path, use_tbb);
}
#endif // BLAKE3_USE_TBB
|