Commit 10b4aece authored by Dmitri Gribenko's avatar Dmitri Gribenko
Browse files

Revert "Avoid creating an immutable map in the Automaton class."

This reverts commit 051d3303. It broke
buildbots, for example,
http://lab.llvm.org:8011/builders/clang-x86_64-debian-fast/builds/21908.
parent 0734fb21
Loading
Loading
Loading
Loading
+22 −41
Original line number Diff line number Diff line
@@ -154,42 +154,29 @@ public:
};
} // namespace internal

// Type representing a transition in the DFA state.
// The action type can be a custom type.
template <typename ActionT> struct TransitionType {
  using StateT = unsigned;
  StateT FromDfaState; // The transitioned-from DFA state.
  ActionT Action;      // The input symbol that causes this transition.
  StateT ToDfaState;   // The transitioned-to DFA state.
  unsigned InfoIdx;    // Start index into TransitionInfo.
};

/// A deterministic finite-state automaton. The automaton is defined in
/// TableGen; this object drives an automaton defined by tblgen-emitted tables.
///
/// An automaton accepts a sequence of input tokens ("actions"). This class is
/// templated on the type of these actions.
template <typename ActionT> class Automaton {
  using TransitionT = TransitionType<ActionT>;
  using TransitionKeyT = std::pair<decltype(TransitionT::FromDfaState),
                                   decltype(TransitionT::Action)>;
  using StateT = typename TransitionT::StateT;
  /// Map from {State, Action} to {NewState, TransitionInfoIdx}.
  /// TransitionInfoIdx is used by the DfaTranscriber to analyze the transition.
  ArrayRef<TransitionT> TransitionMap;
  /// FIXME: This uses a std::map because ActionT can be a pair type including
  /// an enum. In particular DenseMapInfo<ActionT> must be defined to use
  /// DenseMap here.
  /// This is a shared_ptr to allow very quick copy-construction of Automata; this
  /// state is immutable after construction so this is safe.
  using MapTy = std::map<std::pair<uint64_t, ActionT>, std::pair<uint64_t, unsigned>>;
  std::shared_ptr<MapTy> M;
  /// An optional transcription object. This uses much more state than simply
  /// traversing the DFA for acceptance, so is heap allocated.
  std::shared_ptr<internal::NfaTranscriber> Transcriber;
  /// The initial DFA state is 1.
  StateT State = 1;
  uint64_t State = 1;
  /// True if we should transcribe and false if not (even if Transcriber is defined).
  bool Transcribe;

  static bool transitionLessThan(const TransitionT &A,
                                 const TransitionKeyT &B) {
    return std::make_pair(A.FromDfaState, A.Action) < B;
  }

public:
  /// Create an automaton.
  /// \param Transitions The Transitions table as created by TableGen. Note that
@@ -202,24 +189,21 @@ public:
  /// NFA taken by the DFA. NOTE: This is substantially more work than simply
  /// driving the DFA, so unless you require the getPaths() method leave this
  /// empty.
  Automaton(ArrayRef<TransitionT> Transitions,
  template <typename InfoT>
  Automaton(ArrayRef<InfoT> Transitions,
            ArrayRef<NfaStatePair> TranscriptionTable = {}) {
    if (!TranscriptionTable.empty())
      Transcriber =
          std::make_shared<internal::NfaTranscriber>(TranscriptionTable);
    Transcribe = Transcriber != nullptr;
    TransitionMap = Transitions;
    assert(std::is_sorted(TransitionMap.begin(), TransitionMap.end(),
                          [](const TransitionT &A, const TransitionT &B) {
                            return std::make_pair(A.FromDfaState, A.Action) <
                                   std::make_pair(B.FromDfaState, B.Action);
                          }) &&
           "The transitions array is expected to be sorted by FromDfaState and "
           "Action");
    M = std::make_shared<MapTy>();
    for (const auto &I : Transitions)
      // Greedily read and cache the transition table.
      M->emplace(std::make_pair(I.FromDfaState, I.Action),
                 std::make_pair(I.ToDfaState, I.InfoIdx));
  }
  Automaton(const Automaton &Other)
      : TransitionMap(Other.TransitionMap), State(Other.State),
        Transcribe(Other.Transcribe) {
      : M(Other.M), State(Other.State), Transcribe(Other.Transcribe) {
    // Transcriber is not thread-safe, so create a new instance on copy.
    if (Other.Transcriber)
      Transcriber = std::make_shared<internal::NfaTranscriber>(
@@ -249,22 +233,19 @@ public:
  /// If this function returns false, all methods are undefined until reset() is
  /// called.
  bool add(const ActionT &A) {
    auto I = lower_bound(TransitionMap.begin(), TransitionMap.end(),
                         std::make_pair(State, A), transitionLessThan);
    if (I == TransitionMap.end() || State != I->FromDfaState || A != I->Action)
    auto I = M->find({State, A});
    if (I == M->end())
      return false;
    if (Transcriber && Transcribe)
      Transcriber->transition(I->InfoIdx);
    State = I->ToDfaState;
      Transcriber->transition(I->second.second);
    State = I->second.first;
    return true;
  }

  /// Return true if the automaton can be transitioned based on input symbol A.
  bool canAdd(const ActionT &A) {
    auto I = lower_bound(TransitionMap.begin(), TransitionMap.end(),
                         std::make_pair(State, A), transitionLessThan);
    return I != TransitionMap.end() && State == I->FromDfaState &&
           A == I->Action;
    auto I = M->find({State, A});
    return I != M->end();
  }

  /// Obtain a set of possible paths through the input nondeterministic
+8 −2
Original line number Diff line number Diff line
@@ -131,9 +131,15 @@ void DfaEmitter::emit(StringRef Name, raw_ostream &OS) {
  OS << "}};\n\n";

  OS << "// A transition in the generated " << Name << " DFA.\n";
  OS << "using " << Name << "Transition = TransitionType<";
  OS << "struct " << Name << "Transition {\n";
  OS << "  unsigned FromDfaState; // The transitioned-from DFA state.\n";
  OS << "  ";
  printActionType(OS);
  OS << ">;\n\n";
  OS << " Action;       // The input symbol that causes this transition.\n";
  OS << "  unsigned ToDfaState;   // The transitioned-to DFA state.\n";
  OS << "  unsigned InfoIdx;      // Start index into " << Name
     << "TransitionInfo.\n";
  OS << "};\n\n";

  OS << "// A table of DFA transitions, ordered by {FromDfaState, Action}.\n";
  OS << "// The initial state is 1, not zero.\n";