[Aptitude-svn-commit] r3871 - in branches/aptitude-0.3/aptitude: . src/generic

Daniel Burrows dburrows at costa.debian.org
Tue Aug 16 23:00:13 UTC 2005


Author: dburrows
Date: Tue Aug 16 23:00:09 2005
New Revision: 3871

Modified:
   branches/aptitude-0.3/aptitude/ChangeLog
   branches/aptitude-0.3/aptitude/src/generic/apt.cc
   branches/aptitude-0.3/aptitude/src/generic/apt.h
   branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver_universe.cc
   branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver_universe.h
Log:
Memoize is_interesting_dep.

Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog	(original)
+++ branches/aptitude-0.3/aptitude/ChangeLog	Tue Aug 16 23:00:09 2005
@@ -1,5 +1,15 @@
 2005-08-16  Daniel Burrows  <dburrows at debian.org>
 
+	* src/generic/aptcache.cc, src/generic/aptitude_resolver.cc, src/generic/aptitude_resolver_universe.cc, src/generic/aptitude_resolver_universe.h:
+
+	  Memoize calls to is_interesting_dep().  The major change caused
+	  by this is that objects in the aptitude_universe store
+	  backpointers to the universe, not the cache (because calls to
+	  is_interesting_dep need to go through the universe).
+
+	  NB: is_interesting_dep could also be a global function in
+	  apt.cc; would it be useful there?
+
 	* src/generic/aptitude_resolver_universe.cc:
 
 	  Redefine is_interesting_dep in terms of "subsumption": a

Modified: branches/aptitude-0.3/aptitude/src/generic/apt.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/apt.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/apt.cc	Tue Aug 16 23:00:09 2005
@@ -48,6 +48,9 @@
 
 using namespace std;
 
+enum interesting_state {uncached = 0, uninteresting, interesting};
+static interesting_state *cached_deps_interesting = NULL;
+
 aptitudeCacheFile *apt_cache_file=NULL;
 signalling_config *aptcfg=NULL;
 pkgRecords *apt_package_records=NULL;
@@ -207,6 +210,11 @@
       apt_source_list=NULL;
     }
 
+  if(cached_deps_interesting)
+    {
+      delete[] cached_deps_interesting;
+    }
+
   aptitudeCacheFile *new_file=new aptitudeCacheFile;
 
   apt_source_list=new pkgSourceList;
@@ -487,3 +495,219 @@
 
   return true;
 }
+
+/** \return \b true if d1 subsumes d2; that is, if one of the
+ *  following holds:
+ *
+ *  (a) d1 and d2 target the same package and are unversioned.
+ *
+ *  (b) d1 and d2 are unversioned and some version of d2's target
+ *      provides the target package of d1.
+ *
+ *  (c) d1 and d2 target the same package, d1 is unversioned, and d2
+ *      is versioned.
+ *
+ *  (c) d1 and d2 target the same package and are versioned
+ *     (with op1 ver1 and op2 ver2 being the operations and versions)
+ *     and:
+ *
+ *       - op1 is >=, op2 is >>, >=, or =, and ver1 <= ver2; or
+ *       - op1 is <=, op2 is <<, <=, or =, and ver1 >= ver2; or
+ *       - op1 is >>, op2 is >>, and ver1 <= ver2; or
+ *       - op1 is >>, op2 is =, and ver1 < ver2; or
+ *       - op1 is <<, op2 is <<, and ver1 >= ver2; or
+ *       - op1 is <<, op2 is =, and ver1 > ver2; or
+ *       - op1 is =, op2 is =, and ver1 = ver2; or
+ *       - op1 is !=, op2 is !=, and ver1 = ver2.
+ */
+static bool subsumes(const pkgCache::DepIterator &d1,
+		     const pkgCache::DepIterator &d2)
+{
+  pkgCache::PkgIterator target1 = const_cast<pkgCache::DepIterator &>(d1).TargetPkg();
+  pkgCache::PkgIterator target2 = const_cast<pkgCache::DepIterator &>(d2).TargetPkg();
+
+  if(!d1.TargetVer())
+    {
+      if(target1 == target2)
+	return true;
+
+      if(d2.TargetVer())
+	return false;
+
+      for(pkgCache::PrvIterator p = target1.ProvidesList();
+	  !p.end(); ++p)
+	if(p.OwnerPkg() == target2)
+	  return true;
+
+      return false;
+    }
+  else
+    {
+      if(target1 != target2)
+	return false;
+
+      if(!d2.TargetVer())
+	return false;
+
+      pkgCache::Dep::DepCompareOp t1 = (pkgCache::Dep::DepCompareOp) (d1->CompareOp &~ pkgCache::Dep::Or);
+      pkgCache::Dep::DepCompareOp t2 = (pkgCache::Dep::DepCompareOp) (d2->CompareOp &~ pkgCache::Dep::Or);
+
+      int cmpresult = _system->VS->DoCmpVersion(d1.TargetVer(), d1.TargetVer()+strlen(d1.TargetVer()),
+						d2.TargetVer(), d2.TargetVer()+strlen(d2.TargetVer()));
+
+      switch(t1)
+	{
+	case pkgCache::Dep::LessEq:
+	  return
+	    (t2 == pkgCache::Dep::Less ||
+	     t2 == pkgCache::Dep::LessEq ||
+	     t2 == pkgCache::Dep::Equals) &&
+	    cmpresult >= 0;
+	case pkgCache::Dep::GreaterEq:
+	  return
+	    (t2 == pkgCache::Dep::Greater ||
+	     t2 == pkgCache::Dep::LessEq ||
+	     t2 == pkgCache::Dep::Equals) &&
+	    cmpresult <= 0;
+	case pkgCache::Dep::Less:
+	  return
+	    (t2 == pkgCache::Dep::Less && cmpresult >= 0) ||
+	    (t2 == pkgCache::Dep::Equals && cmpresult > 0);
+	case pkgCache::Dep::Greater:
+	  return
+	    (t2 == pkgCache::Dep::Greater && cmpresult <= 0) ||
+	    (t2 == pkgCache::Dep::Equals && cmpresult < 0);
+	case pkgCache::Dep::Equals:
+	  return
+	    (t2 == pkgCache::Dep::Equals && cmpresult == 0);
+	case pkgCache::Dep::NotEquals:
+	  return
+	    (t2 == pkgCache::Dep::NotEquals && cmpresult == 0);
+
+	  // These shouldn't happen:
+	case pkgCache::Dep::NoOp:
+	default:
+	  abort();
+	}
+    }
+}
+
+/** \return \b true if the OR group of d1 subsumes the OR group of d2:
+ *  that is, if every member of the OR group containing d2 has a
+ *  subsuming element in the OR group containing d1.
+ */
+static bool or_group_subsumes(const pkgCache::DepIterator &d1,
+			      const pkgCache::DepIterator &d2)
+{
+  pkgCache::DepIterator start1, end1, start2, end2;
+
+  surrounding_or(d1, start1, end1);
+  surrounding_or(d2, start2, end2);
+
+  for(pkgCache::DepIterator i = d1; i != end1; ++i)
+    {
+      bool found = false;
+
+      for(pkgCache::DepIterator j = d2; j != end2; ++j)
+	if(subsumes(i, j))
+	  {
+	    found = true;
+	    break;
+	  }
+
+      if(!found)
+	return false;
+    }
+
+  return true;
+}
+
+
+// Interesting deps are:
+//
+//   - All critical deps
+//   - All recommendations that are currently satisfied
+//   - All recommendations that are unrelated under subsumption to
+//     each recommendation of the current package version.
+static bool internal_is_interesting_dep(const pkgCache::DepIterator &d,
+					pkgDepCache *cache)
+{
+  if(const_cast<pkgCache::DepIterator &>(d).IsCritical())
+    return true;
+  else if(d->Type != pkgCache::Dep::Recommends)
+    return false;
+  else
+    {
+      pkgCache::DepIterator dtmp = d;
+      while(!dtmp.end() && dtmp->CompareOp & pkgCache::Dep::Or)
+	++dtmp;
+      if((*cache)[d] & pkgDepCache::DepGNow)
+	return true;
+
+      pkgCache::VerIterator currver = const_cast<pkgCache::DepIterator &>(d).ParentPkg().CurrentVer();
+      pkgCache::VerIterator parver = const_cast<pkgCache::DepIterator &>(d).ParentVer();
+
+      if(currver == parver)
+	return false;
+      else if(currver.end())
+	return true;
+      else
+	// Check whether the current version of this package has a dep
+	// that either subsumes _or is subsumed by_ this
+	// recommendation.  (for mathematical "correctness" we'd only
+	// check the first direction, but the goal is to not annoy the
+	// user unnecessarily; losing a few new recommendations is OK)
+	//
+	// NB: full correctness without annoyance means actually
+	// TRIMMING DOWN the target set of a recommendation by
+	// subtracting elements that are in the current version's
+	// recommendation list.  Needless to say, I'm ignoring this
+	// for now.
+	{
+	  pkgCache::DepIterator d2 = currver.DependsList();
+
+	  while(!d2.end())
+	    {
+	      if(d2->Type == pkgCache::Dep::Recommends &&
+		 or_group_subsumes(d2, d) || or_group_subsumes(d, d2))
+		return false;
+
+	      while(!d2.end() && ((d2->CompareOp & pkgCache::Dep::Or) != 0))
+		++d2;
+
+	      if(!d2.end())
+		++d2;
+	    }
+
+	  return true;
+	}
+    }
+}
+
+bool is_interesting_dep(const pkgCache::DepIterator &d,
+			pkgDepCache *cache)
+{
+  if(cached_deps_interesting == NULL)
+    {
+      cached_deps_interesting = new interesting_state[cache->Head().DependsCount];
+      for(unsigned long i = 0; i<cache->Head().DependsCount; ++i)
+	cached_deps_interesting[i] = uncached;
+    }
+
+  switch(cached_deps_interesting[d->ID])
+    {
+    case uncached:
+      {
+	bool rval = internal_is_interesting_dep(d, cache);
+
+	cached_deps_interesting[d->ID] = rval ? interesting : uninteresting;
+	return rval;
+      }
+    case interesting:
+      return true;
+    case uninteresting:
+      return false;
+    default:
+      abort();
+    }
+}

Modified: branches/aptitude-0.3/aptitude/src/generic/apt.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/apt.h	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/apt.h	Tue Aug 16 23:00:09 2005
@@ -173,4 +173,15 @@
   }
 };
 
+/** \return \b true if the given dependency is "interesting":
+ *          specifically, if it's either critical or a Recommends
+ *          that's "new" or currently satisfied.
+ *
+ *  \param d the dependency to test
+ *  \param cache the cache in which to check d (used to find out whether
+ *         d is currently satisfied).
+ */
+bool is_interesting_dep(const pkgCache::DepIterator &d,
+			pkgDepCache *cache);
+
 #endif

Modified: branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver_universe.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver_universe.cc	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver_universe.cc	Tue Aug 16 23:00:09 2005
@@ -6,195 +6,6 @@
 
 using namespace std;
 
-/** \return \b true if d1 subsumes d2; that is, if one of the
- *  following holds:
- *
- *  (a) d1 and d2 target the same package and are unversioned.
- *
- *  (b) d1 and d2 are unversioned and some version of d2's target
- *      provides the target package of d1.
- *
- *  (c) d1 and d2 target the same package, d1 is unversioned, and d2
- *      is versioned.
- *
- *  (c) d1 and d2 target the same package and are versioned
- *     (with op1 ver1 and op2 ver2 being the operations and versions)
- *     and:
- *
- *       - op1 is >=, op2 is >>, >=, or =, and ver1 <= ver2; or
- *       - op1 is <=, op2 is <<, <=, or =, and ver1 >= ver2; or
- *       - op1 is >>, op2 is >>, and ver1 <= ver2; or
- *       - op1 is >>, op2 is =, and ver1 < ver2; or
- *       - op1 is <<, op2 is <<, and ver1 >= ver2; or
- *       - op1 is <<, op2 is =, and ver1 > ver2; or
- *       - op1 is =, op2 is =, and ver1 = ver2; or
- *       - op1 is !=, op2 is !=, and ver1 = ver2.
- */
-static bool subsumes(const pkgCache::DepIterator &d1,
-		     const pkgCache::DepIterator &d2)
-{
-  pkgCache::PkgIterator target1 = const_cast<pkgCache::DepIterator &>(d1).TargetPkg();
-  pkgCache::PkgIterator target2 = const_cast<pkgCache::DepIterator &>(d2).TargetPkg();
-
-  if(!d1.TargetVer())
-    {
-      if(target1 == target2)
-	return true;
-
-      if(d2.TargetVer())
-	return false;
-
-      for(pkgCache::PrvIterator p = target1.ProvidesList();
-	  !p.end(); ++p)
-	if(p.OwnerPkg() == target2)
-	  return true;
-
-      return false;
-    }
-  else
-    {
-      if(target1 != target2)
-	return false;
-
-      if(!d2.TargetVer())
-	return false;
-
-      pkgCache::Dep::DepCompareOp t1 = (pkgCache::Dep::DepCompareOp) (d1->CompareOp &~ pkgCache::Dep::Or);
-      pkgCache::Dep::DepCompareOp t2 = (pkgCache::Dep::DepCompareOp) (d2->CompareOp &~ pkgCache::Dep::Or);
-
-      int cmpresult = _system->VS->DoCmpVersion(d1.TargetVer(), d1.TargetVer()+strlen(d1.TargetVer()),
-						d2.TargetVer(), d2.TargetVer()+strlen(d2.TargetVer()));
-
-      switch(t1)
-	{
-	case pkgCache::Dep::LessEq:
-	  return
-	    (t2 == pkgCache::Dep::Less ||
-	     t2 == pkgCache::Dep::LessEq ||
-	     t2 == pkgCache::Dep::Equals) &&
-	    cmpresult >= 0;
-	case pkgCache::Dep::GreaterEq:
-	  return
-	    (t2 == pkgCache::Dep::Greater ||
-	     t2 == pkgCache::Dep::LessEq ||
-	     t2 == pkgCache::Dep::Equals) &&
-	    cmpresult <= 0;
-	case pkgCache::Dep::Less:
-	  return
-	    (t2 == pkgCache::Dep::Less && cmpresult >= 0) ||
-	    (t2 == pkgCache::Dep::Equals && cmpresult > 0);
-	case pkgCache::Dep::Greater:
-	  return
-	    (t2 == pkgCache::Dep::Greater && cmpresult <= 0) ||
-	    (t2 == pkgCache::Dep::Equals && cmpresult < 0);
-	case pkgCache::Dep::Equals:
-	  return
-	    (t2 == pkgCache::Dep::Equals && cmpresult == 0);
-	case pkgCache::Dep::NotEquals:
-	  return
-	    (t2 == pkgCache::Dep::NotEquals && cmpresult == 0);
-
-	  // These shouldn't happen:
-	case pkgCache::Dep::NoOp:
-	default:
-	  abort();
-	}
-    }
-}
-
-/** \return \b true if the OR group of d1 subsumes the OR group of d2:
- *  that is, if every member of the OR group containing d2 has a
- *  subsuming element in the OR group containing d1.
- */
-static bool or_group_subsumes(const pkgCache::DepIterator &d1,
-			      const pkgCache::DepIterator &d2)
-{
-  pkgCache::DepIterator start1, end1, start2, end2;
-
-  surrounding_or(d1, start1, end1);
-  surrounding_or(d2, start2, end2);
-
-  for(pkgCache::DepIterator i = d1; i != end1; ++i)
-    {
-      bool found = false;
-
-      for(pkgCache::DepIterator j = d2; j != end2; ++j)
-	if(subsumes(i, j))
-	  {
-	    found = true;
-	    break;
-	  }
-
-      if(!found)
-	return false;
-    }
-
-  return true;
-}
-
-// This should be a static member of the universe object, but it's
-// rather awkward to put it there right now.
-//
-// Interesting deps are:
-//
-//   - All critical deps
-//   - All recommendations that are currently satisfied
-//   - All recommendations that are unrelated under subsumption to
-//     each recommendation of the current package version.
-inline bool aptitude_universe::is_interesting_dep(const pkgCache::DepIterator &d)
-{
-  if(const_cast<pkgCache::DepIterator &>(d).IsCritical())
-    return true;
-  else if(d->Type != pkgCache::Dep::Recommends)
-    return false;
-  else
-    {
-      pkgCache::DepIterator dtmp = d;
-      while(!dtmp.end() && dtmp->CompareOp & pkgCache::Dep::Or)
-	++dtmp;
-      if((*apt_cache_file)[d] & pkgDepCache::DepGNow)
-	return true;
-
-      pkgCache::VerIterator currver = const_cast<pkgCache::DepIterator &>(d).ParentPkg().CurrentVer();
-      pkgCache::VerIterator parver = const_cast<pkgCache::DepIterator &>(d).ParentVer();
-
-      if(currver == parver)
-	return false;
-      else if(currver.end())
-	return true;
-      else
-	// Check whether the current version of this package has a dep
-	// that either subsumes _or is subsumed by_ this
-	// recommendation.  (for mathematical "correctness" we'd only
-	// check the first direction, but the goal is to not annoy the
-	// user unnecessarily; losing a few new recommendations is OK)
-	//
-	// NB: full correctness without annoyance means actually
-	// TRIMMING DOWN the target set of a recommendation by
-	// subtracting elements that are in the current version's
-	// recommendation list.  Needless to say, I'm ignoring this
-	// for now.
-	{
-	  pkgCache::DepIterator d2 = currver.DependsList();
-
-	  while(!d2.end())
-	    {
-	      if(d2->Type == pkgCache::Dep::Recommends &&
-		 or_group_subsumes(d2, d) || or_group_subsumes(d, d2))
-		return false;
-
-	      while(!d2.end() && ((d2->CompareOp & pkgCache::Dep::Or) != 0))
-		++d2;
-
-	      if(!d2.end())
-		++d2;
-	    }
-
-	  return true;
-	}
-    }
-}
-
 string aptitude_resolver_version::get_name() const
 {
   if(!ver.end())
@@ -237,7 +48,7 @@
 
 bool aptitude_resolver_version::revdep_iterator::applicable() const
 {
-  if(!aptitude_universe::is_interesting_dep(dep_lst))
+  if(!is_interesting_dep(dep_lst, cache))
     return false;
 
   // Unversioned deps always apply.
@@ -255,7 +66,7 @@
 void aptitude_resolver_version::revdep_iterator::normalize()
 {
   while(!dep_lst.end() &&
-	(!aptitude_universe::is_interesting_dep(dep_lst) || !applicable()))
+	(!is_interesting_dep(dep_lst, cache) || !applicable()))
     ++dep_lst;
 
   if(dep_lst.end() && !provides_open)
@@ -266,7 +77,7 @@
 	{
 	  dep_lst=prv_lst.ParentPkg().RevDependsList();
 	  while(!dep_lst.end() &&
-		(!aptitude_universe::is_interesting_dep(dep_lst) || !applicable()))
+		(!is_interesting_dep(dep_lst, cache) || !applicable()))
 	    ++dep_lst;
 	}
       provides_open=true;
@@ -284,7 +95,7 @@
 	  dep_lst=prv_lst.ParentPkg().RevDependsList();
 
 	  while(!dep_lst.end() &&
-		(!aptitude_universe::is_interesting_dep(dep_lst) || !applicable()))
+		(!is_interesting_dep(dep_lst, cache) || !applicable()))
 	    ++dep_lst;
 	}
     }
@@ -317,7 +128,7 @@
   // dependency.
   while(!dep.end() &&
 	(dep.ParentPkg() == dep.TargetPkg() ||
-	 !aptitude_universe::is_interesting_dep(dep)))
+	 !is_interesting_dep(dep, cache)))
     ++dep;
 
   // If we ran out of deps, we're done!
@@ -562,7 +373,7 @@
 void aptitude_universe::broken_dep_iterator::normalize()
 {
   while(!the_dep.end() &&
-	!(aptitude_universe::is_interesting_dep(the_dep) &&
+	!(is_interesting_dep(the_dep, cache) &&
 	  dep_is_inst_broken(the_dep)))
     ++the_dep;
 
@@ -584,7 +395,7 @@
 	    the_dep=ver.DependsList();
 
 	  while(!the_dep.end() &&
-		!(aptitude_universe::is_interesting_dep(the_dep) &&
+		!(is_interesting_dep(the_dep, cache) &&
 		  dep_is_inst_broken(the_dep)))
 	    ++the_dep;
 
@@ -593,7 +404,7 @@
 	}
     }
 
-  assert(the_dep.end() || aptitude_universe::is_interesting_dep(the_dep));
+  assert(the_dep.end() || is_interesting_dep(the_dep, cache));
 
   // Now dep is a broken critical dep or an end dep.  If it is a
   // conflicts, we might need to push down into Provides...

Modified: branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver_universe.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver_universe.h	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/aptitude_resolver_universe.h	Tue Aug 16 23:00:09 2005
@@ -877,8 +877,6 @@
     // PackageCount is added to make room for the UNINST versions.
     return cache->Head().VersionCount+cache->Head().PackageCount;
   }
-
-  static bool is_interesting_dep(const pkgCache::DepIterator &d);
 };
 
 #endif



More information about the Aptitude-svn-commit mailing list