@@ -7,19 +7,19 @@ use std::collections::HashSet as Set;
77use std:: sync:: Arc ;
88
99use crate :: internal:: {
10- Arena , DecisionLevel , IncompDpId , Incompatibility , PartialSolution , Relation , SatisfierSearch ,
11- SmallVec ,
10+ Arena , DecisionLevel , HashArena , Id , IncompDpId , Incompatibility , PartialSolution , Relation ,
11+ SatisfierSearch , SmallVec ,
1212} ;
1313use crate :: { DependencyProvider , DerivationTree , Map , NoSolutionError , VersionSet } ;
1414
1515/// Current state of the PubGrub algorithm.
1616#[ derive( Clone ) ]
1717pub ( crate ) struct State < DP : DependencyProvider > {
18- root_package : DP :: P ,
18+ pub root_package : Id < DP :: P > ,
1919 root_version : DP :: V ,
2020
2121 #[ allow( clippy:: type_complexity) ]
22- incompatibilities : Map < DP :: P , Vec < IncompDpId < DP > > > ,
22+ incompatibilities : Map < Id < DP :: P > , Vec < IncompDpId < DP > > > ,
2323
2424 /// Store the ids of incompatibilities that are already contradicted.
2525 /// For each one keep track of the decision level when it was found to be contradicted.
@@ -29,7 +29,7 @@ pub(crate) struct State<DP: DependencyProvider> {
2929 /// All incompatibilities expressing dependencies,
3030 /// with common dependents merged.
3131 #[ allow( clippy:: type_complexity) ]
32- merged_dependencies : Map < ( DP :: P , DP :: P ) , SmallVec < IncompDpId < DP > > > ,
32+ merged_dependencies : Map < ( Id < DP :: P > , Id < DP :: P > ) , SmallVec < IncompDpId < DP > > > ,
3333
3434 /// Partial solution.
3535 /// TODO: remove pub.
@@ -38,29 +38,35 @@ pub(crate) struct State<DP: DependencyProvider> {
3838 /// The store is the reference storage for all incompatibilities.
3939 pub ( crate ) incompatibility_store : Arena < Incompatibility < DP :: P , DP :: VS , DP :: M > > ,
4040
41+ /// The store is the reference storage for all packages.
42+ pub ( crate ) package_store : HashArena < DP :: P > ,
43+
4144 /// This is a stack of work to be done in `unit_propagation`.
4245 /// It can definitely be a local variable to that method, but
4346 /// this way we can reuse the same allocation for better performance.
44- unit_propagation_buffer : SmallVec < DP :: P > ,
47+ unit_propagation_buffer : SmallVec < Id < DP :: P > > ,
4548}
4649
4750impl < DP : DependencyProvider > State < DP > {
4851 /// Initialization of PubGrub state.
4952 pub ( crate ) fn init ( root_package : DP :: P , root_version : DP :: V ) -> Self {
5053 let mut incompatibility_store = Arena :: new ( ) ;
54+ let mut package_store = HashArena :: new ( ) ;
55+ let root_package = package_store. alloc ( root_package) ;
5156 let not_root_id = incompatibility_store. alloc ( Incompatibility :: not_root (
52- root_package. clone ( ) ,
57+ root_package,
5358 root_version. clone ( ) ,
5459 ) ) ;
5560 let mut incompatibilities = Map :: default ( ) ;
56- incompatibilities. insert ( root_package. clone ( ) , vec ! [ not_root_id] ) ;
61+ incompatibilities. insert ( root_package, vec ! [ not_root_id] ) ;
5762 Self {
5863 root_package,
5964 root_version,
6065 incompatibilities,
6166 contradicted_incompatibilities : Map :: default ( ) ,
6267 partial_solution : PartialSolution :: empty ( ) ,
6368 incompatibility_store,
69+ package_store,
6470 unit_propagation_buffer : SmallVec :: Empty ,
6571 merged_dependencies : Map :: default ( ) ,
6672 }
@@ -75,18 +81,19 @@ impl<DP: DependencyProvider> State<DP> {
7581 /// Add an incompatibility to the state.
7682 pub ( crate ) fn add_incompatibility_from_dependencies (
7783 & mut self ,
78- package : DP :: P ,
84+ package : Id < DP :: P > ,
7985 version : DP :: V ,
8086 deps : impl IntoIterator < Item = ( DP :: P , DP :: VS ) > ,
8187 ) -> std:: ops:: Range < IncompDpId < DP > > {
8288 // Create incompatibilities and allocate them in the store.
8389 let new_incompats_id_range =
8490 self . incompatibility_store
85- . alloc_iter ( deps. into_iter ( ) . map ( |dep| {
91+ . alloc_iter ( deps. into_iter ( ) . map ( |( dep_p, dep_vs) | {
92+ let dep_pid = self . package_store . alloc ( dep_p) ;
8693 Incompatibility :: from_dependency (
87- package. clone ( ) ,
94+ package,
8895 <DP :: VS as VersionSet >:: singleton ( version. clone ( ) ) ,
89- dep ,
96+ ( dep_pid , dep_vs ) ,
9097 )
9198 } ) ) ;
9299 // Merge the newly created incompatibilities with the older ones.
@@ -98,7 +105,10 @@ impl<DP: DependencyProvider> State<DP> {
98105
99106 /// Unit propagation is the core mechanism of the solving algorithm.
100107 /// CF <https://github.com/dart-lang/pub/blob/master/doc/solver.md#unit-propagation>
101- pub ( crate ) fn unit_propagation ( & mut self , package : DP :: P ) -> Result < ( ) , NoSolutionError < DP > > {
108+ pub ( crate ) fn unit_propagation (
109+ & mut self ,
110+ package : Id < DP :: P > ,
111+ ) -> Result < ( ) , NoSolutionError < DP > > {
102112 self . unit_propagation_buffer . clear ( ) ;
103113 self . unit_propagation_buffer . push ( package) ;
104114 while let Some ( current_package) = self . unit_propagation_buffer . pop ( ) {
@@ -120,7 +130,7 @@ impl<DP: DependencyProvider> State<DP> {
120130 Relation :: Satisfied => {
121131 log:: info!(
122132 "Start conflict resolution because incompat satisfied:\n {}" ,
123- current_incompat
133+ current_incompat. display ( & self . package_store )
124134 ) ;
125135 conflict_id = Some ( incompat_id) ;
126136 break ;
@@ -131,7 +141,7 @@ impl<DP: DependencyProvider> State<DP> {
131141 // but so does allocating a hash map and hashing each item.
132142 // In practice `unit_propagation_buffer` is small enough that we can just do a linear scan.
133143 if !self . unit_propagation_buffer . contains ( & package_almost) {
134- self . unit_propagation_buffer . push ( package_almost. clone ( ) ) ;
144+ self . unit_propagation_buffer . push ( package_almost) ;
135145 }
136146 // Add (not term) to the partial solution with incompat as cause.
137147 self . partial_solution . add_derivation (
@@ -157,7 +167,7 @@ impl<DP: DependencyProvider> State<DP> {
157167 self . build_derivation_tree ( terminal_incompat_id)
158168 } ) ?;
159169 self . unit_propagation_buffer . clear ( ) ;
160- self . unit_propagation_buffer . push ( package_almost. clone ( ) ) ;
170+ self . unit_propagation_buffer . push ( package_almost) ;
161171 // Add to the partial solution with incompat as cause.
162172 self . partial_solution . add_derivation (
163173 package_almost,
@@ -180,12 +190,12 @@ impl<DP: DependencyProvider> State<DP> {
180190 fn conflict_resolution (
181191 & mut self ,
182192 incompatibility : IncompDpId < DP > ,
183- ) -> Result < ( DP :: P , IncompDpId < DP > ) , IncompDpId < DP > > {
193+ ) -> Result < ( Id < DP :: P > , IncompDpId < DP > ) , IncompDpId < DP > > {
184194 let mut current_incompat_id = incompatibility;
185195 let mut current_incompat_changed = false ;
186196 loop {
187197 if self . incompatibility_store [ current_incompat_id]
188- . is_terminal ( & self . root_package , & self . root_version )
198+ . is_terminal ( self . root_package , & self . root_version )
189199 {
190200 return Err ( current_incompat_id) ;
191201 } else {
@@ -197,7 +207,6 @@ impl<DP: DependencyProvider> State<DP> {
197207 SatisfierSearch :: DifferentDecisionLevels {
198208 previous_satisfier_level,
199209 } => {
200- let package = package. clone ( ) ;
201210 self . backtrack (
202211 current_incompat_id,
203212 current_incompat_changed,
@@ -213,7 +222,7 @@ impl<DP: DependencyProvider> State<DP> {
213222 package,
214223 & self . incompatibility_store ,
215224 ) ;
216- log:: info!( "prior cause: {}" , prior_cause) ;
225+ log:: info!( "prior cause: {}" , prior_cause. display ( & self . package_store ) ) ;
217226 current_incompat_id = self . incompatibility_store . alloc ( prior_cause) ;
218227 current_incompat_changed = true ;
219228 }
@@ -256,19 +265,16 @@ impl<DP: DependencyProvider> State<DP> {
256265 fn merge_incompatibility ( & mut self , mut id : IncompDpId < DP > ) {
257266 if let Some ( ( p1, p2) ) = self . incompatibility_store [ id] . as_dependency ( ) {
258267 // If we are a dependency, there's a good chance we can be merged with a previous dependency
259- let deps_lookup = self
260- . merged_dependencies
261- . entry ( ( p1. clone ( ) , p2. clone ( ) ) )
262- . or_default ( ) ;
268+ let deps_lookup = self . merged_dependencies . entry ( ( p1, p2) ) . or_default ( ) ;
263269 if let Some ( ( past, merged) ) = deps_lookup. as_mut_slice ( ) . iter_mut ( ) . find_map ( |past| {
264270 self . incompatibility_store [ id]
265271 . merge_dependents ( & self . incompatibility_store [ * past] )
266272 . map ( |m| ( past, m) )
267273 } ) {
268274 let new = self . incompatibility_store . alloc ( merged) ;
269- for ( pkg, _) in self . incompatibility_store [ new] . iter ( ) {
275+ for ( & pkg, _) in self . incompatibility_store [ new] . iter ( ) {
270276 self . incompatibilities
271- . entry ( pkg. clone ( ) )
277+ . entry ( pkg)
272278 . or_default ( )
273279 . retain ( |id| id != past) ;
274280 }
@@ -278,14 +284,11 @@ impl<DP: DependencyProvider> State<DP> {
278284 deps_lookup. push ( id) ;
279285 }
280286 }
281- for ( pkg, term) in self . incompatibility_store [ id] . iter ( ) {
287+ for ( & pkg, term) in self . incompatibility_store [ id] . iter ( ) {
282288 if cfg ! ( debug_assertions) {
283289 assert_ne ! ( term, & crate :: term:: Term :: any( ) ) ;
284290 }
285- self . incompatibilities
286- . entry ( pkg. clone ( ) )
287- . or_default ( )
288- . push ( id) ;
291+ self . incompatibilities . entry ( pkg) . or_default ( ) . push ( id) ;
289292 }
290293 }
291294
@@ -320,6 +323,7 @@ impl<DP: DependencyProvider> State<DP> {
320323 id,
321324 & shared_ids,
322325 & self . incompatibility_store ,
326+ & self . package_store ,
323327 & precomputed,
324328 ) ;
325329 precomputed. insert ( id, Arc :: new ( tree) ) ;
0 commit comments