/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef RecurseGuard_h__ #define RecurseGuard_h__ #include "Utils.h" // This class acts as a tracker for avoiding infinite recursion when traversing // chains in CFGs etc. // // Constructing a RecurseGuard sets up a shared backing store which tracks the // currently observed objects. Whenever recursing, use RecurseGuard.recurse(T) // to construct another RecurseGuard with the same backing store. // // The RecurseGuard object will unregister its object when it is destroyed, and // has a method `isRepeat()` which will return `true` if the item was already // seen. template class RecurseGuard { public: RecurseGuard(T Thing) : Thing(Thing), Set(new DenseSet()), Repeat(false) { Set->insert(Thing); } RecurseGuard(T Thing, std::shared_ptr> &Set) : Thing(Thing), Set(Set), Repeat(false) { Repeat = !Set->insert(Thing).second; } RecurseGuard(const RecurseGuard &) = delete; RecurseGuard(RecurseGuard &&Other) : Thing(Other.Thing), Set(Other.Set), Repeat(Other.Repeat) { Other.Repeat = true; } ~RecurseGuard() { if (!Repeat) { Set->erase(Thing); } } bool isRepeat() { return Repeat; } T get() { return Thing; } operator T() { return Thing; } T operator->() { return Thing; } RecurseGuard recurse(T NewThing) { return RecurseGuard(NewThing, Set); } private: T Thing; std::shared_ptr> Set; bool Repeat; }; #endif // RecurseGuard_h__