LLVM API Documentation
00001 //===--- DeltaAlgorithm.cpp - A Set Minimization Algorithm -----*- C++ -*--===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 //===----------------------------------------------------------------------===// 00008 00009 #include "llvm/ADT/DeltaAlgorithm.h" 00010 #include <algorithm> 00011 #include <iterator> 00012 using namespace llvm; 00013 00014 DeltaAlgorithm::~DeltaAlgorithm() { 00015 } 00016 00017 bool DeltaAlgorithm::GetTestResult(const changeset_ty &Changes) { 00018 if (FailedTestsCache.count(Changes)) 00019 return false; 00020 00021 bool Result = ExecuteOneTest(Changes); 00022 if (!Result) 00023 FailedTestsCache.insert(Changes); 00024 00025 return Result; 00026 } 00027 00028 void DeltaAlgorithm::Split(const changeset_ty &S, changesetlist_ty &Res) { 00029 // FIXME: Allow clients to provide heuristics for improved splitting. 00030 00031 // FIXME: This is really slow. 00032 changeset_ty LHS, RHS; 00033 unsigned idx = 0, N = S.size() / 2; 00034 for (changeset_ty::const_iterator it = S.begin(), 00035 ie = S.end(); it != ie; ++it, ++idx) 00036 ((idx < N) ? LHS : RHS).insert(*it); 00037 if (!LHS.empty()) 00038 Res.push_back(LHS); 00039 if (!RHS.empty()) 00040 Res.push_back(RHS); 00041 } 00042 00043 DeltaAlgorithm::changeset_ty 00044 DeltaAlgorithm::Delta(const changeset_ty &Changes, 00045 const changesetlist_ty &Sets) { 00046 // Invariant: union(Res) == Changes 00047 UpdatedSearchState(Changes, Sets); 00048 00049 // If there is nothing left we can remove, we are done. 00050 if (Sets.size() <= 1) 00051 return Changes; 00052 00053 // Look for a passing subset. 00054 changeset_ty Res; 00055 if (Search(Changes, Sets, Res)) 00056 return Res; 00057 00058 // Otherwise, partition the sets if possible; if not we are done. 00059 changesetlist_ty SplitSets; 00060 for (changesetlist_ty::const_iterator it = Sets.begin(), 00061 ie = Sets.end(); it != ie; ++it) 00062 Split(*it, SplitSets); 00063 if (SplitSets.size() == Sets.size()) 00064 return Changes; 00065 00066 return Delta(Changes, SplitSets); 00067 } 00068 00069 bool DeltaAlgorithm::Search(const changeset_ty &Changes, 00070 const changesetlist_ty &Sets, 00071 changeset_ty &Res) { 00072 // FIXME: Parallelize. 00073 for (changesetlist_ty::const_iterator it = Sets.begin(), 00074 ie = Sets.end(); it != ie; ++it) { 00075 // If the test passes on this subset alone, recurse. 00076 if (GetTestResult(*it)) { 00077 changesetlist_ty Sets; 00078 Split(*it, Sets); 00079 Res = Delta(*it, Sets); 00080 return true; 00081 } 00082 00083 // Otherwise, if we have more than two sets, see if test passes on the 00084 // complement. 00085 if (Sets.size() > 2) { 00086 // FIXME: This is really slow. 00087 changeset_ty Complement; 00088 std::set_difference( 00089 Changes.begin(), Changes.end(), it->begin(), it->end(), 00090 std::insert_iterator<changeset_ty>(Complement, Complement.begin())); 00091 if (GetTestResult(Complement)) { 00092 changesetlist_ty ComplementSets; 00093 ComplementSets.insert(ComplementSets.end(), Sets.begin(), it); 00094 ComplementSets.insert(ComplementSets.end(), it + 1, Sets.end()); 00095 Res = Delta(Complement, ComplementSets); 00096 return true; 00097 } 00098 } 00099 } 00100 00101 return false; 00102 } 00103 00104 DeltaAlgorithm::changeset_ty DeltaAlgorithm::Run(const changeset_ty &Changes) { 00105 // Check empty set first to quickly find poor test functions. 00106 if (GetTestResult(changeset_ty())) 00107 return changeset_ty(); 00108 00109 // Otherwise run the real delta algorithm. 00110 changesetlist_ty Sets; 00111 Split(Changes, Sets); 00112 00113 return Delta(Changes, Sets); 00114 }