23 inline bool try_compute_hash(
hash::
hash_provider<T>& in_hash_provider, std::ifstream& in_file, T& out_hash,
bool in_from_beginning, hash_progress_callback_t<T> in_callback)
27 if (!in_file.is_open())
30 const auto start_pos = uint64_t(in_file.tellg());
32 in_file.seekg(0, std::ios::end);
34 const auto length = uint64_t(in_file.tellg());
36 in_file.seekg(in_from_beginning ? 0 : start_pos, std::ios::beg);
38 char buffer[k_optimal_buffer_size]{};
42 in_file.read(buffer,
sizeof(buffer));
44 const auto count = uint64_t(in_file.gcount());
49 in_hash_provider.update(
reinterpret_cast<uint8_t*>(buffer), count);
52 if (in_callback && !in_callback(in_hash_provider.digest(), uint64_t(in_file.tellg()), length))
62 in_file.seekg(start_pos, std::ios::beg);
64 out_hash = in_hash_provider.digest();
80 std::error_code error_code{};
82 if (!std::filesystem::exists(in_path, error_code))
85 auto file = std::ifstream(in_path, std::ios::binary);
87 return try_compute_hash(in_hash_provider, file, out_hash,
true, in_callback);
99 inline bool compare(std::ifstream& in_left, std::ifstream& in_right,
bool in_from_beginning, hash_progress_callback_t<
typename T::type> in_left_callback, hash_progress_callback_t<
typename T::type> in_right_callback)
103 if (!in_left.is_open() || !in_right.is_open())
106 const auto left_start_pos = uint64_t(in_left.tellg());
107 const auto right_start_pos = uint64_t(in_right.tellg());
110 in_left.seekg(0, std::ios::end);
111 in_right.seekg(0, std::ios::end);
113 const auto left_length = uint64_t(in_left.tellg());
114 const auto right_length = uint64_t(in_right.tellg());
117 if (left_length == right_length)
119 in_left.seekg(in_from_beginning ? 0 : left_start_pos, std::ios::beg);
120 in_right.seekg(in_from_beginning ? 0 : right_start_pos, std::ios::beg);
123 constexpr auto hash_checkpoint_interval = mem::align<uint64_t>(16 * 1024 * 1024, k_optimal_buffer_size);
126 const auto hash_checkpoint_count = (left_length + hash_checkpoint_interval - 1) / hash_checkpoint_interval;
129 auto hash_checkpoints = std::vector<
typename T::type>(hash_checkpoint_count);
131 uint64_t hash_checkpoint_index{};
133 const auto left_hash_checkpoint_callback = [&](
typename T::type in_hash, uint64_t in_processed_bytes, uint64_t in_total_bytes) ->
bool
135 if ((in_processed_bytes % hash_checkpoint_interval) == 0)
138 hash_checkpoints[hash_checkpoint_index] = in_hash;
139 hash_checkpoint_index++;
142 if (in_left_callback)
143 return in_left_callback(in_hash, in_processed_bytes, in_total_bytes);
148 const auto right_hash_checkpoint_callback = [&](
typename T::type in_hash, uint64_t in_processed_bytes, uint64_t in_total_bytes) ->
bool
150 if ((in_processed_bytes % hash_checkpoint_interval) == 0)
153 if (hash_checkpoints[hash_checkpoint_index] != in_hash)
156 hash_checkpoint_index++;
159 if (in_right_callback)
160 return in_right_callback(in_hash, in_processed_bytes, in_total_bytes);
165 typename T::type left_hash{};
167 const auto left_callback = hash_checkpoint_count
168 ? left_hash_checkpoint_callback
171 if (try_compute_hash<T>(in_left, left_hash, in_from_beginning, left_callback))
173 typename T::type right_hash{};
175 const auto right_callback = hash_checkpoint_count
176 ? right_hash_checkpoint_callback
179 hash_checkpoint_index = 0;
181 if (try_compute_hash<T>(in_right, right_hash, in_from_beginning, right_callback))
182 result = left_hash == right_hash;
186 in_left.seekg(left_start_pos, std::ios::beg);
187 in_right.seekg(right_start_pos, std::ios::beg);
193 inline bool compare(
const std::filesystem::path& in_left,
const std::filesystem::path& in_right, hash_progress_callback_t<
typename T::type> in_left_callback, hash_progress_callback_t<
typename T::type> in_right_callback)
195 std::error_code error_code{};
197 if (!std::filesystem::exists(in_left, error_code) || !std::filesystem::exists(in_right, error_code) || error_code)
200 if (in_left == in_right)
204 if (std::filesystem::file_size(in_left, error_code) != std::filesystem::file_size(in_right, error_code) || error_code)
207 auto left = std::ifstream(in_left, std::ios::binary);
208 auto right = std::ifstream(in_right, std::ios::binary);
210 return compare(left, right,
true, in_left_callback, in_right_callback);
215 auto file = std::ifstream(in_path, std::ios::binary);
220 auto buffer = std::vector<
char>(k_optimal_buffer_size);
222 file.read(buffer.data(), k_optimal_buffer_size);
224 const auto length = size_t(file.gcount());
229 ? ut::encoding::encoding_type(simdutf::BOM::check_bom(buffer.data(), length))
230 : ut::encoding::unknown;
234 ? ut::encoding::encoding_type(simdutf::autodetect_encoding(buffer.data(), length))
235 : ut::encoding::unknown;
253 std::error_code error_code{};
255 if (!std::filesystem::exists(in_path, error_code))
259 const auto encoding = get_encoding(in_path, &bom);
260 const auto bom_length = ut::
encoding::get_bom_length(bom);
262 auto file = std::ifstream(in_path, std::ios::binary | std::ios::ate);
267 const auto length = int64_t(file.tellg()) - bom_length;
272 auto buffer = std::vector<
char>(length);
275 file.seekg(bom_length, std::ios::beg);
278 file.rdbuf()->sgetn(buffer.data(), length);
282 switch (ut::expr::get_encoding_char_size(native_encoding))
284 case sizeof(
char16_t):
285 result = ut::encoding::convert<T>(std::u16string_view(
reinterpret_cast<
const char16_t*>(buffer.data()), length /
sizeof(
char16_t)), native_encoding, encoding);
288 case sizeof(
char32_t):
289 result = ut::encoding::convert<T>(std::u32string_view(
reinterpret_cast<
const char32_t*>(buffer.data()), length /
sizeof(
char32_t)), native_encoding, encoding);
293 result = ut::encoding::convert<T>(std::string_view(buffer.data(), length), native_encoding, encoding);
301 inline bool write_all_text(
const std::filesystem::path& in_path,
const T& in_str,
bool in_write_bom)
303 const auto str = ut::
encoding::convert<target_encoding>(in_str);
308 auto file = std::ofstream(in_path, std::ios::binary);
315 const auto bom = get_bom(target_encoding);
316 file.write(
reinterpret_cast<
const char*>(bom.data()), bom.size());
319 file.write(
reinterpret_cast<
const char*>(str.data()), str.size() *
sizeof(ut::expr::get_encoding_char_type_t<target_encoding>));