#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include "revng/TupleTree/Tracking.h" #include "revng/TupleTree/Visits.h" namespace revng { struct TrackingImpl { 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(); } }; struct StopTrackingVisitor { template static void visitKeyedObjectContainer(const Type &CurrentItem) { CurrentItem.stopTracking(); } template static void visitTupleElement(const Type &CurrentItem) { CurrentItem.template getTracker().stopTracking(); } }; 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 &UP, TupleTreePath &Stack, ReadFields &Info) { if (!UP.isEmpty()) { UP.upcast([&](auto &Upcasted) { // Don't forget to add the kind of the polymorphic object to the stack. Stack.push_back(Upcasted.Kind()); collectImpl(Upcasted, Stack, Info); Stack.pop_back(); }); } } 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); using KeyType = std::remove_cv_t; for (KeyType 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; Stack.push_back(KeyedObjectTraits::key(LHSElement)); collectImpl(LHSElement, Stack, Info); Stack.pop_back(); } } template static void collectImpl(const T &LHS, TupleTreePath &Stack, ReadFields &Info) {} 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 &UP) { if (!UP.isEmpty()) UP.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) {} }; template ReadFields Tracking::collect(const M &LHS) { stop(LHS); TupleTreePath Stack; ReadFields Info; TrackingImpl::collectImpl(LHS, Stack, Info); clearAndResume(LHS); return Info; } template void Tracking::clearAndResume(const M &LHS) { TrackingImpl::visitTuple(LHS); } template void Tracking::push(const M &LHS) { TrackingImpl::visitTuple(LHS); } template void Tracking::pop(const M &LHS) { TrackingImpl::visitTuple(LHS); } template void Tracking::stop(const M &LHS) { TrackingImpl::visitTuple(LHS); } } // namespace revng