#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include "revng/ADT/KeyedObjectContainer.h" #include "revng/ADT/TrackingContainer.h" #include "revng/ADT/UpcastablePointer.h" #include "revng/Support/YAMLTraits.h" #include "revng/TupleTree/TupleLikeTraits.h" #include "revng/TupleTree/TupleTreeCompatible.h" #include "revng/TupleTree/TupleTreePath.h" #include "revng/TupleTree/Visits.h" /// Struct returned by Tracking::collect. /// The field Read is the set of paths of fields that were accessed. /// The exact vectors contains the paths of all vectors that were marked as /// requiring being identical. struct ReadFields { std::set Read; std::set ExactVectors; }; namespace revng { struct Tracking { private: struct PopVisitor { template static void visitKeyedObjectContainer(const Type &CurrentItem) { CurrentItem.trackingPop(); } template static void visitTupleElement(const Type &CurrentItem) { CurrentItem.template getTracker().pop(); } }; struct PushVisitor { template static void visitKeyedObjectContainer(const Type &CurrentItem) { CurrentItem.trackingPush(); } template static void visitTupleElement(const Type &CurrentItem) { CurrentItem.template getTracker().push(); } }; struct ClearVisitor { template static void visitKeyedObjectContainer(const Type &CurrentItem) { CurrentItem.clearTracking(); } template static void visitTupleElement(const Type &CurrentItem) { CurrentItem.template getTracker().clear(); } }; private: template static void collectTuple(const T &LHS, TupleTreePath &Stack, ReadFields &Info) { if constexpr (I < std::tuple_size_v) { Stack.push_back(size_t(I)); if (LHS.template getTracker().isSet()) Info.Read.insert(Stack); collectImpl(LHS.template untrackedGet(), Stack, Info); Stack.pop_back(); // Recur collectTuple(LHS, Stack, Info); } } template T> static void collectImpl(const T &LHS, TupleTreePath &Stack, ReadFields &Info) { LHS.upcast([&](auto &Upcasted) { collectImpl(Upcasted, Stack, Info); }); } template static void collectImpl(const T &LHS, TupleTreePath &Stack, ReadFields &Info) { collectTuple(LHS, Stack, Info); } template static void collectImpl(const T &LHS, TupleTreePath &Stack, ReadFields &Info) { typename T::TrackingResult TrackingResult = LHS.getTrackingResult(); if (TrackingResult.Exact) Info.ExactVectors.insert(Stack); for (auto &Key : TrackingResult.InspectedKeys) { Stack.push_back(Key); Info.Read.insert(Stack); Stack.pop_back(); } for (auto &LHSElement : LHS.Content) { using value_type = typename T::value_type; if constexpr (TupleSizeCompatible) Stack.push_back(LHSElement.untrackedKey()); else Stack.push_back(KeyedObjectTraits::key(LHSElement)); collectImpl(LHSElement, Stack, Info); Stack.pop_back(); } } template static void collectImpl(const T &LHS, TupleTreePath &Stack, ReadFields &Info) {} private: template static void visitTuple(const T &LHS) { if constexpr (I < std::tuple_size_v) { visitImpl(LHS.template untrackedGet()); Visitor::template visitTupleElement(LHS); // Recur visitTuple(LHS); } } template T> static void visitImpl(T &LHS) { LHS.upcast([&](const auto &Upcasted) { visitImpl(Upcasted); }); } template static void visitImpl(const T &LHS) { visitTuple(LHS); } template static void visitImpl(const T &LHS) { for (auto &LHSElement : LHS.Content) { visitImpl(LHSElement); } Visitor::template visitKeyedObjectContainer(LHS); } template static void visitImpl(const T &LHS) {} public: template static ReadFields collect(const M &LHS) { TupleTreePath Stack; ReadFields Info; collectImpl(LHS, Stack, Info); return Info; } template static void clear(const M &LHS) { visitTuple(LHS); } template static void push(const M &LHS) { visitTuple(LHS); } template static void pop(const M &LHS) { visitTuple(LHS); } }; } // namespace revng