blob: b2b5184436df9b153cfa9d8395eda139d2ae03da [file] [log] [blame]
// Copyright (c) 2024, 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 '../piece/piece.dart';
import 'solution.dart';
import 'solver.dart';
/// Maintains a cache of [Piece] subtrees that have been previously solved.
///
/// If a given [Piece] has newlines before and after it, then (in most cases,
/// assuming there are no other constraints) the way it is formatted only
/// depends on its leading indentation. In that case, we can format that piece
/// using a separate Solver and insert the results in any Solution that has
/// that piece at that leading indentation.
///
/// This cache stores those previously formatted subtree pieces so that
/// [CodeWriter] can reuse them across [Solution]s.
///
/// Note that this cache is shared across all Solvers and Solutions for an
/// entire format operation. Different Solvers and Solutions may end up reaching
/// the same child Piece and wanting to format it separately with the same
/// indentation. When that happens, sharing this cache allows us to reuse that
/// cached subtree Solution.
class SolutionCache {
final _cache = <_Key, Solution>{};
/// Returns a previously cached solution for formatting [root] with leading
/// [indent] or produces a new solution, caches it, and returns it.
///
/// If [root] is already bound to a state in the surrounding piece tree's
/// [Solution], then [stateIfBound] is that state. Otherwise, it is treated
/// as unbound and the cache will find a state for [root] as well as its
/// children.
Solution find(int pageWidth, Piece root, int indent, State? stateIfBound) {
// See if we've already formatted this piece at this indentation. If not,
// format it and store the result.
return _cache.putIfAbsent(
(root, indent: indent),
() => Solver(this, pageWidth: pageWidth, leadingIndent: indent)
.format(root, stateIfBound));
}
}
/// The key used to uniquely identify a previously formatted Piece.
///
/// Each subtree solution depends only on the Piece and the amount of leading
/// indentation in the context where it appears (which may vary based on how
/// surrounding pieces end up splitting).
///
/// In particular, note that if surrounding pieces split in *different* ways
/// that still end up producing the same overall leading indentation, we are
/// able to reuse a previously cached Solution for some Piece.
typedef _Key = (Piece, {int indent});