diff options
Diffstat (limited to '')
-rw-r--r-- | build/clang-plugin/RecurseGuard.h | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/build/clang-plugin/RecurseGuard.h b/build/clang-plugin/RecurseGuard.h new file mode 100644 index 0000000000..5daf55a9e8 --- /dev/null +++ b/build/clang-plugin/RecurseGuard.h @@ -0,0 +1,56 @@ +/* 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 <typename T> class RecurseGuard { +public: + RecurseGuard(T Thing) : Thing(Thing), Set(new DenseSet<T>()), Repeat(false) { + Set->insert(Thing); + } + RecurseGuard(T Thing, std::shared_ptr<DenseSet<T>> &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<DenseSet<T>> Set; + bool Repeat; +}; + +#endif // RecurseGuard_h__ |