Pith - whittle
#include "core/Comparator.h"
#include <cstdlib>
#include <QSet>

namespace whittle {
	namespace {

		bool timeDiffers(std::int64_t a, std::int64_t b, std::int64_t tolNs) {
			return std::llabs(a - b) > tolNs;
		}

		bool isNewer(std::int64_t a, std::int64_t b, std::int64_t tolNs) {
			return (a - b) > tolNs;
		}

		QSet<QString> impliedParents(const QHash<QString, FileRecord>& source) {
			QSet<QString> out;
			for (auto it = source.constBegin(); it != source.constEnd(); ++it) {
				const QString& key = it.key();
				for (int p = key.indexOf('/'); p > 0; p = key.indexOf('/', p + 1))
					out.insert(key.left(p));
			}
			return out;
		}

	} 

	DiffResult Comparator::compare(const QHash<QString, FileRecord>& source,
		const QHash<QString, FileRecord>& usb,
		const FilterSettings& f) {
		DiffResult r;

		for (auto it = source.constBegin(); it != source.constEnd(); ++it) {
			const FileRecord& s = it.value();
			const auto u = usb.constFind(it.key());

			if (u == usb.constEnd()) {
				r.sourceRows.append(s);
				r.mergeList.append(s);
				if (!s.isDir) { ++r.newFileCount; r.newBytes += s.size; }
				continue;
			}

			if (s.isDir) {
				if (f.display == FilterSettings::Display::All)
					r.sourceRows.append(s);
				continue;
			}

			const bool sizeDiff = f.compareSize && (s.size != u->size);
			const bool timeDiff = f.compareTime &&
			timeDiffers(s.mtimeNs, u->mtimeNs, f.toleranceNs);

			if (sizeDiff || timeDiff) {
				++r.diffFileCount;
				r.diffBytes += s.size;
				r.diffPaths.insert(it.key());
				r.mergeList.append(s);
				if (isNewer(u->mtimeNs, s.mtimeNs, f.toleranceNs))
					r.destNewerPaths.insert(it.key());
			}
			if (sizeDiff || timeDiff || f.display == FilterSettings::Display::All)
				r.sourceRows.append(s);

		}

		const QSet<QString> parents = impliedParents(source);
		for (auto it = usb.constBegin(); it != usb.constEnd(); ++it) {
			if (source.contains(it.key())) continue;
			if (it->isDir && parents.contains(it.key())) continue;
			r.usbOnlyRows.append(it.value());
		}

		return r;
	}

}