DiagramSpatialIndex.incremental constructor

DiagramSpatialIndex.incremental(
  1. DiagramSpatialIndex previous,
  2. List<ResolvedElement> elements, {
  3. Iterable<int>? changedIndexes,
  4. Iterable<String>? changedIds,
})

Implementation

factory DiagramSpatialIndex.incremental(
  DiagramSpatialIndex previous,
  List<ResolvedElement> elements, {
  Iterable<int>? changedIndexes,
  Iterable<String>? changedIds,
}) {
  if (previous._elements.length != elements.length) changedIndexes = null;
  final positions =
      changedIndexes != null && previous._elements.length == elements.length
      ? previous._positions
      : {for (var i = 0; i < elements.length; i++) elements[i].id: i};
  var cells = previous._cells;
  var copiedMap = false;
  var global = previous._global;
  final copiedCells = <(int, int)>{};
  var copiedGlobal = false;

  List<String> mutableCell((int, int) key) {
    if (!copiedMap) {
      cells = cells.fork();
      copiedMap = true;
    }
    if (!cells.containsKey(key)) {
      copiedCells.add(key);
      cells[key] = <String>[];
    } else if (copiedCells.add(key)) {
      cells[key] = [...?cells[key]];
    }
    return cells[key]!;
  }

  final ids =
      changedIds ??
      (changedIndexes != null
          ? changedIndexes.map((i) => elements[i].id)
          : <String>{...previous._positions.keys, ...positions.keys});
  for (final id in ids) {
    final oldIndex = previous._positions[id], newIndex = positions[id];
    final before = oldIndex == null ? null : previous._elements[oldIndex];
    final after = newIndex == null ? null : elements[newIndex];
    if (identical(before, after)) continue;
    final oldCells = before == null
        ? const <(int, int)>[]
        : _cellsFor(before.bounds);
    final newCells = after == null
        ? const <(int, int)>[]
        : _cellsFor(after.bounds);
    // Membership is unchanged for most small moves and appearance edits.
    // Query filtering reads the new element bounds; buckets only hold stable identities.
    if (oldCells == null && newCells == null) continue;
    if (oldCells != null &&
        newCells != null &&
        oldCells.length == newCells.length &&
        Iterable.generate(oldCells.length)
            .every((index) => oldCells[index] == newCells[index])) {
      continue;
    }
    if (oldCells == null) {
      if (!copiedGlobal) {
        global = [...global];
        copiedGlobal = true;
      }
      global.remove(id);
    } else {
      for (final key in oldCells) {
        final bucket = mutableCell(key)..remove(id);
        if (bucket.isEmpty) cells.remove(key);
      }
    }
    if (newCells == null) {
      if (!copiedGlobal) {
        global = [...global];
        copiedGlobal = true;
      }
      global.add(id);
    } else {
      for (final key in newCells) {
        mutableCell(key).add(id);
      }
    }
  }
  return DiagramSpatialIndex._(
    DiagramPersistentList<ResolvedElement>.snapshot(elements),
    cells,
    copiedGlobal ? List.unmodifiable(global) : global,
    positions,
  );
}