113 lines
3.5 KiB
C++
113 lines
3.5 KiB
C++
/*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
|
*/
|
|
|
|
#include "emory/chunk/params.hpp"
|
|
#include "emory/chunk/map.hpp"
|
|
#include "emory/chunk/match.hpp"
|
|
#include "emory/chunk/ostream.hpp"
|
|
|
|
#include <cruft/util/io.hpp>
|
|
#include <cruft/util/parse/value.hpp>
|
|
|
|
#include <cstddef>
|
|
#include <iostream>
|
|
|
|
|
|
enum {
|
|
ARG_SELF,
|
|
ARG_BITS,
|
|
ARG_WINDOW,
|
|
ARGS_MINIMUM,
|
|
ARGS_TARGET,
|
|
ARGS_SOURCE,
|
|
|
|
NUM_ARGS,
|
|
};
|
|
|
|
|
|
int main (int argc, char const **argv)
|
|
{
|
|
if (argc < NUM_ARGS) {
|
|
std::cerr << "usage: " << argv[ARG_SELF] << " <bits> <window> <minimum> <target> <source> [...]\n";
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
emory::chunk::params const p {
|
|
.bits = cruft::parse::from_string<std::size_t> (argv[ARG_BITS ]),
|
|
.window = cruft::parse::from_string<std::size_t> (argv[ARG_WINDOW]),
|
|
.minimum = cruft::parse::from_string<std::ptrdiff_t> (argv[ARGS_MINIMUM]),
|
|
};
|
|
|
|
std::clog << "Hashing target\n";
|
|
emory::chunk::map target (cruft::mapped_file (argv[ARGS_TARGET]), p);
|
|
std::sort (target.elements.begin (), target.elements.end (), emory::chunk::region::digest_ordering {});
|
|
std::cout << "Found " << target.elements.size () << " chunks\n";
|
|
|
|
std::vector<emory::chunk::match<int>> found;
|
|
|
|
for (int i = ARGS_SOURCE; i != argc; ++i) {
|
|
auto const path = argv[i];
|
|
std::clog << "Hashing source: " << path << '\n';
|
|
emory::chunk::map source (cruft::mapped_file (path), p);
|
|
std::sort (source.elements.begin (), source.elements.end (), emory::chunk::region::digest_ordering {});
|
|
|
|
std::clog << "Finding common\n";
|
|
auto const &source_matches = common (target, source);
|
|
std::clog << "Discovered " << source_matches.size () << " blocks\n";
|
|
|
|
std::transform (
|
|
std::begin (source_matches),
|
|
std::end (source_matches),
|
|
std::back_inserter (found),
|
|
[&] (auto const &j) -> emory::chunk::match<int>
|
|
{
|
|
return {
|
|
.src = { i, j.src.data },
|
|
.dst = { ARGS_TARGET, j.dst.data },
|
|
};
|
|
});
|
|
|
|
std::sort (
|
|
std::begin (found),
|
|
std::end (found),
|
|
emory::chunk::match<int>::src_ordering {}
|
|
);
|
|
|
|
found.erase (
|
|
std::unique (
|
|
std::begin (found),
|
|
std::end (found),
|
|
emory::chunk::match<int>::dst_equality {}
|
|
),
|
|
found.end ()
|
|
);
|
|
}
|
|
|
|
std::clog << "Finalising\n";
|
|
std::size_t matching = 0;
|
|
std::vector<std::size_t> source_bytes (argc - ARGS_SOURCE, 0);
|
|
for (auto const &i: found) {
|
|
std::cout << i << '\n';
|
|
auto const size = i.dst.data.offset.second - i.dst.data.offset.first;
|
|
matching += size;
|
|
source_bytes[i.src.id - ARGS_SOURCE] += size;
|
|
}
|
|
|
|
std::size_t const total = std::accumulate (
|
|
target.elements.begin (),
|
|
target.elements.end (),
|
|
0u,
|
|
[] (auto const &a, auto const &b) { return a + b.offset.second - b.offset.first; }
|
|
);
|
|
|
|
std::cout << "Found " << found.size () << " chunks. " << matching << "/" << total << " bytes for a factor of " << float (matching) / total << "\n";
|
|
|
|
for (int i = ARGS_SOURCE; i != argc; ++i)
|
|
std::cerr << argv[i] << " contributed: " << source_bytes[i - ARGS_SOURCE] << '\n';
|
|
}
|