sanitizer_list.h revision 1.1.1.3
1//===-- sanitizer_list.h ----------------------------------------*- C++ -*-===//
2//
3// This file is distributed under the University of Illinois Open Source
4// License. See LICENSE.TXT for details.
5//
6//===----------------------------------------------------------------------===//
7//
8// This file contains implementation of a list class to be used by
9// ThreadSanitizer, etc run-times.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef SANITIZER_LIST_H
14#define SANITIZER_LIST_H
15
16#include "sanitizer_internal_defs.h"
17
18namespace __sanitizer {
19
20// Intrusive singly-linked list with size(), push_back(), push_front()
21// pop_front(), append_front() and append_back().
22// This class should be a POD (so that it can be put into TLS)
23// and an object with all zero fields should represent a valid empty list.
24// This class does not have a CTOR, so clear() should be called on all
25// non-zero-initialized objects before using.
26template<class Item>
27struct IntrusiveList {
28  friend class Iterator;
29
30  void clear() {
31    first_ = last_ = nullptr;
32    size_ = 0;
33  }
34
35  bool empty() const { return size_ == 0; }
36  uptr size() const { return size_; }
37
38  void push_back(Item *x) {
39    if (empty()) {
40      x->next = nullptr;
41      first_ = last_ = x;
42      size_ = 1;
43    } else {
44      x->next = nullptr;
45      last_->next = x;
46      last_ = x;
47      size_++;
48    }
49  }
50
51  void push_front(Item *x) {
52    if (empty()) {
53      x->next = nullptr;
54      first_ = last_ = x;
55      size_ = 1;
56    } else {
57      x->next = first_;
58      first_ = x;
59      size_++;
60    }
61  }
62
63  void pop_front() {
64    CHECK(!empty());
65    first_ = first_->next;
66    if (!first_)
67      last_ = nullptr;
68    size_--;
69  }
70
71  Item *front() { return first_; }
72  Item *back() { return last_; }
73
74  void append_front(IntrusiveList<Item> *l) {
75    CHECK_NE(this, l);
76    if (l->empty())
77      return;
78    if (empty()) {
79      *this = *l;
80    } else if (!l->empty()) {
81      l->last_->next = first_;
82      first_ = l->first_;
83      size_ += l->size();
84    }
85    l->clear();
86  }
87
88  void append_back(IntrusiveList<Item> *l) {
89    CHECK_NE(this, l);
90    if (l->empty())
91      return;
92    if (empty()) {
93      *this = *l;
94    } else {
95      last_->next = l->first_;
96      last_ = l->last_;
97      size_ += l->size();
98    }
99    l->clear();
100  }
101
102  void CheckConsistency() {
103    if (size_ == 0) {
104      CHECK_EQ(first_, 0);
105      CHECK_EQ(last_, 0);
106    } else {
107      uptr count = 0;
108      for (Item *i = first_; ; i = i->next) {
109        count++;
110        if (i == last_) break;
111      }
112      CHECK_EQ(size(), count);
113      CHECK_EQ(last_->next, 0);
114    }
115  }
116
117  template<class ListTy, class ItemTy>
118  class IteratorBase {
119   public:
120    explicit IteratorBase(ListTy *list)
121        : list_(list), current_(list->first_) { }
122    ItemTy *next() {
123      ItemTy *ret = current_;
124      if (current_) current_ = current_->next;
125      return ret;
126    }
127    bool hasNext() const { return current_ != nullptr; }
128   private:
129    ListTy *list_;
130    ItemTy *current_;
131  };
132
133  typedef IteratorBase<IntrusiveList<Item>, Item> Iterator;
134  typedef IteratorBase<const IntrusiveList<Item>, const Item> ConstIterator;
135
136// private, don't use directly.
137  uptr size_;
138  Item *first_;
139  Item *last_;
140};
141
142} // namespace __sanitizer
143
144#endif // SANITIZER_LIST_H
145