| // Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'dart:collection' show Queue; | |
| import '../elements/entities.dart'; | |
| import 'algorithm_state.dart'; | |
| import 'entity_data.dart'; | |
| import 'import_set.dart'; | |
| /// The entity_data_state work queue. | |
| class WorkQueue { | |
| /// The actual queue of work that needs to be done. | |
| final Queue<WorkItem> queue = Queue(); | |
| /// An index to find work items in the queue corresponding to a given | |
| /// [EntityData]. | |
| final Map<EntityData, WorkItem> pendingWorkItems = {}; | |
| /// Lattice used to compute unions of [ImportSet]s. | |
| final ImportSetLattice _importSets; | |
| /// Registry used to create [EntityData]. | |
| final EntityDataRegistry _registry; | |
| WorkQueue(this._importSets, this._registry); | |
| /// Whether there are no more work items in the queue. | |
| bool get isNotEmpty => queue.isNotEmpty; | |
| /// Pop the next element in the queue. | |
| WorkItem nextItem() { | |
| assert(isNotEmpty); | |
| return queue.removeFirst(); | |
| } | |
| /// Add to the queue that [element] should be updated to include all imports | |
| /// in [importSet]. If there is already a work item in the queue for | |
| /// [element], this makes sure that the work item now includes the union of | |
| /// [importSet] and the existing work item's import set. | |
| void addEntityData(EntityData entityData, ImportSet importSet) { | |
| var item = pendingWorkItems[entityData]; | |
| if (item == null) { | |
| item = WorkItem(entityData, importSet); | |
| pendingWorkItems[entityData] = item; | |
| queue.add(item); | |
| } else { | |
| item.importsToAdd = _importSets.union(item.importsToAdd, importSet); | |
| } | |
| } | |
| void addMember(MemberEntity member, ImportSet importSet) { | |
| addEntityData(_registry.createMemberEntityData(member), importSet); | |
| } | |
| void addClass(ClassEntity cls, ImportSet importSet) { | |
| addEntityData(_registry.createClassEntityData(cls), importSet); | |
| } | |
| /// Processes the next item in the queue. | |
| void processNextItem(AlgorithmState state) { | |
| var item = nextItem(); | |
| var entityData = item.entityData; | |
| pendingWorkItems.remove(entityData); | |
| state.processEntity(entityData); | |
| ImportSet oldSet = state.entityToSet[entityData] ?? _importSets.emptySet; | |
| ImportSet newSet = _importSets.union(oldSet, item.importsToAdd); | |
| state.update(entityData, oldSet, newSet); | |
| } | |
| } | |
| /// Summary of the work that needs to be done on a class, member, or constant. | |
| class WorkItem { | |
| final EntityData entityData; | |
| /// Additional imports that use [element] or [value] and need to be added by | |
| /// the algorithm. | |
| /// | |
| /// This is non-final in case we add more deferred imports to the set before | |
| /// the work item is applied (see [WorkQueue.addElement] and | |
| /// [WorkQueue.addConstant]). | |
| ImportSet importsToAdd; | |
| WorkItem(this.entityData, this.importsToAdd); | |
| } |