//===--- DeltaAlgorithm.cpp - A Set Minimization Algorithm -----*- C++ -*--===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===// #include "llvm/ADT/DeltaAlgorithm.h" #include #include #include using namespace llvm; DeltaAlgorithm::~DeltaAlgorithm() = default; bool DeltaAlgorithm::GetTestResult(const changeset_ty &Changes) { if (FailedTestsCache.count(Changes)) return false; bool Result = ExecuteOneTest(Changes); if (!Result) FailedTestsCache.insert(Changes); return Result; } void DeltaAlgorithm::Split(const changeset_ty &S, changesetlist_ty &Res) { // FIXME: Allow clients to provide heuristics for improved splitting. // FIXME: This is really slow. changeset_ty LHS, RHS; unsigned idx = 0, N = S.size() / 2; for (changeset_ty::const_iterator it = S.begin(), ie = S.end(); it != ie; ++it, ++idx) ((idx < N) ? LHS : RHS).insert(*it); if (!LHS.empty()) Res.push_back(LHS); if (!RHS.empty()) Res.push_back(RHS); } DeltaAlgorithm::changeset_ty DeltaAlgorithm::Delta(const changeset_ty &Changes, const changesetlist_ty &Sets) { // Invariant: union(Res) == Changes UpdatedSearchState(Changes, Sets); // If there is nothing left we can remove, we are done. if (Sets.size() <= 1) return Changes; // Look for a passing subset. changeset_ty Res; if (Search(Changes, Sets, Res)) return Res; // Otherwise, partition the sets if possible; if not we are done. changesetlist_ty SplitSets; for (const changeset_ty &Set : Sets) Split(Set, SplitSets); if (SplitSets.size() == Sets.size()) return Changes; return Delta(Changes, SplitSets); } bool DeltaAlgorithm::Search(const changeset_ty &Changes, const changesetlist_ty &Sets, changeset_ty &Res) { // FIXME: Parallelize. for (changesetlist_ty::const_iterator it = Sets.begin(), ie = Sets.end(); it != ie; ++it) { // If the test passes on this subset alone, recurse. if (GetTestResult(*it)) { changesetlist_ty Sets; Split(*it, Sets); Res = Delta(*it, Sets); return true; } // Otherwise, if we have more than two sets, see if test passes on the // complement. if (Sets.size() > 2) { // FIXME: This is really slow. changeset_ty Complement; std::set_difference(Changes.begin(), Changes.end(), it->begin(), it->end(), std::inserter(Complement, Complement.begin())); if (GetTestResult(Complement)) { changesetlist_ty ComplementSets; ComplementSets.insert(ComplementSets.end(), Sets.begin(), it); ComplementSets.insert(ComplementSets.end(), it + 1, Sets.end()); Res = Delta(Complement, ComplementSets); return true; } } } return false; } DeltaAlgorithm::changeset_ty DeltaAlgorithm::Run(const changeset_ty &Changes) { // Check empty set first to quickly find poor test functions. if (GetTestResult(changeset_ty())) return changeset_ty(); // Otherwise run the real delta algorithm. changesetlist_ty Sets; Split(Changes, Sets); return Delta(Changes, Sets); }