|
@@ -0,0 +1,68 @@
|
|
|
+import {Delta} from "./delta";
|
|
|
+
|
|
|
+export class CompositeDelta implements Delta {
|
|
|
+ readonly dependencies: Array<CompositeDelta>;
|
|
|
+ readonly conflicts: Array<CompositeDelta>;
|
|
|
+
|
|
|
+ constructor(dependencies: Array<CompositeDelta>, conflicts: Array<CompositeDelta>) {
|
|
|
+ this.dependencies = dependencies;
|
|
|
+ this.conflicts = conflicts;
|
|
|
+ }
|
|
|
+
|
|
|
+ getDependencies(): Array<CompositeDelta> {
|
|
|
+ return this.dependencies;
|
|
|
+ }
|
|
|
+
|
|
|
+ getConflicts(): Array<CompositeDelta> {
|
|
|
+ return this.conflicts;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export class CompositeLevel {
|
|
|
+ containedBy: Map<Delta, CompositeDelta> = new Map();
|
|
|
+
|
|
|
+ createComposite(deltas: Array<Delta>) {
|
|
|
+ const dependencies: Array<CompositeDelta> = [];
|
|
|
+ const conflicts: Array<CompositeDelta> = [];
|
|
|
+
|
|
|
+ for (const delta of deltas) {
|
|
|
+ if (this.containedBy.has(delta)) {
|
|
|
+ throw new Error("Assertion failed: delta already part of another composite");
|
|
|
+ }
|
|
|
+ for (const dependency of delta.getDependencies()) {
|
|
|
+ const compositeDependency = this.containedBy.get(dependency);
|
|
|
+ if (compositeDependency === undefined) {
|
|
|
+ throw new Error("Assertion failed: cannot find composite of " + dependency.constructor.name);
|
|
|
+ }
|
|
|
+ if (!dependencies.includes(compositeDependency)) {
|
|
|
+ dependencies.push(compositeDependency);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (const conflict of delta.getConflicts()) {
|
|
|
+ const compositeConflict = this.containedBy.get(conflict);
|
|
|
+ if (compositeConflict === undefined) {
|
|
|
+ throw new Error("Assertion failed: cannot find composite of " + conflict.constructor.name);
|
|
|
+ }
|
|
|
+ if (!conflicts.includes(compositeConflict)) {
|
|
|
+ conflicts.push(compositeConflict);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dependencies.some(dependency => conflicts.includes(dependency))) {
|
|
|
+ throw new Error("Assertion failed: overlap between dependencies and conflicts");
|
|
|
+ }
|
|
|
+
|
|
|
+ const composite = new CompositeDelta(dependencies, conflicts);
|
|
|
+
|
|
|
+ for (const delta of deltas) {
|
|
|
+ this.containedBy.set(delta, composite);
|
|
|
+ }
|
|
|
+ for (const compositeConflict of conflicts) {
|
|
|
+ // Conflicts are symmetric, so newly created conflicts are also added to the other:
|
|
|
+ compositeConflict.conflicts.push(composite);
|
|
|
+ }
|
|
|
+
|
|
|
+ return composite;
|
|
|
+ }
|
|
|
+}
|