summaryrefslogtreecommitdiffstats
path: root/build/clang-plugin/RecurseGuard.h
blob: 5daf55a9e8d8e9d736cc2e780bed77dfef4e4eb5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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__