#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(); } }; // Uncomment the following for easier debugging: // #define RECURSIVE_COLLECT_TUPLE #ifdef RECURSIVE_COLLECT_TUPLE 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.push_back(Stack); } collectImpl(LHS.template untrackedGet(), Stack, Info); Stack.pop_back(); // Recur collectTuple(LHS, Stack, Info); } } #endif template T> static void collectImpl(const T &UP, TupleTreePath &Stack, ReadFields &Info) { if (!UP.isEmpty()) { auto KindTrackingSuspender = UP.get()->KindTracker.suspend(); UP.upcast([&](auto &Upcasted) { // Don't forget to add the kind of the polymorphic object to the stack. static_assert(!std::is_const_v< std::remove_reference_t>); Stack.push_back(Upcasted.Kind()); collectImpl(Upcasted, Stack, Info); Stack.pop_back(); }); } } #ifdef RECURSIVE_COLLECT_TUPLE template static void collectImpl(const T &LHS, TupleTreePath &Stack, ReadFields &Info) { collectTuple(LHS, Stack, Info); } #else // collectImpl remains unchanged template static void collectImpl(const T &LHS, TupleTreePath &Stack, ReadFields &Info) { collectTuple(LHS, Stack, Info); } // Helper function with index sequence template static void collectTupleImpl(const T &LHS, TupleTreePath &Stack, ReadFields &Info, std::index_sequence) { // Use a fold expression to process each index (..., (Stack.push_back(Is), (LHS.template getTracker().isSet() ? (Info.Read.push_back(Stack), void()) : void()), collectImpl(LHS.template untrackedGet(), Stack, Info), Stack.pop_back())); } // Main function using index sequence template static void collectTuple(const T &LHS, TupleTreePath &Stack, ReadFields &Info) { collectTupleImpl(LHS, Stack, Info, std::make_index_sequence>{}); } #endif template static void collectImpl(const T &LHS, TupleTreePath &Stack, ReadFields &Info) { typename T::TrackingResult TrackingResult = LHS.getTrackingResult(); if (TrackingResult.Exact) Info.ExactVectors.push_back(Stack); using KeyType = std::remove_cv_t; for (KeyType Key : TrackingResult.InspectedKeys) { Stack.push_back(Key); Info.Read.push_back(Stack); Stack.pop_back(); } for (auto &LHSElement : LHS.Content) { using value_type = typename T::value_type; using Type = decltype(LHSElement); auto &Mutable = const_cast &>(LHSElement); static_assert(!std::is_const_v< std::remove_reference_t>); Stack.push_back(KeyedObjectTraits::key(Mutable)); 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()) { auto KindTrackingSuspender = UP.get()->KindTracker.suspend(); 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); Info.deduplicate(); 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