tlds
Transactional Operations for Linked Data Structures
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
DList.hpp
Go to the documentation of this file.
1 /**
2  * Copyright (C) 2011
3  * University of Rochester Department of Computer Science
4  * and
5  * Lehigh University Department of Computer Science and Engineering
6  *
7  * License: Modified BSD
8  * Please see the file LICENSE.RSTM for licensing information
9  */
10 
11 #ifndef DLIST_HPP__
12 #define DLIST_HPP__
13 
14 #include <limits.h>
15 #include <api/api.hpp>
16 
17 // Doubly-Linked List workload
18 class DList
19 {
20  // Node is a node in the DList
21  struct Node
22  {
23  int m_val;
26 
27  // basic constructor
28  Node(int val) : m_val(val), m_prev(), m_next() { }
29  };
30 
31  public:
32 
33  // the dlist keeps head and tail pointers, for bidirectional traversal
36 
37  DList();
38 
39  // insert a node if it doesn't already exist
41  void insert(int val TM_ARG);
42 
43  // true iff val is in the data structure
45  bool lookup(int val TM_ARG) const;
46 
47  // remove a node if its value = val
49  void remove(int val TM_ARG);
50 
51  // make sure the list is in sorted order
52  bool isSane() const;
53 
54  // increment all elements, moving forward
57 
58  // increment all elements, moving in reverse
61 
62  // increment every seqth element, starting with start, moving forward
64  void increment_forward_pattern(int start, int seq TM_ARG);
65 
66  // increment every seqth element, starting with start, moving backward
68  void increment_backward_pattern(int start, int seq TM_ARG);
69 
70  // read the whole list, then increment every element in the chunk
71  // starting at chunk_num*chunk_size
73  void increment_chunk(int chunk_num, int chunk_size TM_ARG);
74 };
75 
76 
77 // constructor: head and tail have extreme values, point to each other
78 DList::DList() : head(new Node(-1)), tail(new Node(INT_MAX))
79 {
80  head->m_next = tail;
81  tail->m_prev = head;
82 }
83 
84 // simple sanity check: make sure all elements of the list are in sorted order
85 bool DList::isSane(void) const
86 {
87  bool sane = false;
88  sane = true;
89 
90  // forward traversal
91  const Node* prev(head);
92  const Node* curr((prev->m_next));
93  while (curr != NULL) {
94  // ensure sorted order
95  if ((prev->m_val) >= (curr->m_val)) {
96  sane = false;
97  break;
98  }
99  // ensure curr->prev->next == curr
100  const Node* p ((curr->m_prev));
101  if ((p->m_next) != curr) {
102  sane = false;
103  break;
104  }
105 
106  prev = curr;
107  curr = (curr->m_next);
108  }
109 
110  // backward traversal
111  prev = tail;
112  curr = (prev->m_prev);
113  while (curr != NULL) {
114  // ensure sorted order
115  if ((prev->m_val) < (curr->m_val)) {
116  sane = false;
117  break;
118  }
119  // ensure curr->next->prev == curr
120  const Node* n ((curr->m_next));
121  if ((n->m_prev) != curr) {
122  sane = false;
123  break;
124  }
125 
126  prev = curr;
127  curr = (curr->m_prev);
128  }
129  return sane;
130 }
131 
132 // insert method; find the right place in the list, add val so that it is in
133 // sorted order; if val is already in the list, exit without inserting
135 void DList::insert(int val TM_ARG)
136 {
137  // traverse the list to find the insertion point
138  const Node* prev(head);
139  const Node* curr(TM_READ(prev->m_next));
140 
141  while (curr != NULL) {
142  if (TM_READ(curr->m_val) >= val)
143  break;
144 
145  prev = curr;
146  curr = TM_READ(prev->m_next);
147  }
148 
149  // now insert new_node between prev and curr
150  if (TM_READ(curr->m_val) > val) {
151  Node* before = const_cast<Node*>(prev);
152  Node* after = const_cast<Node*>(curr);
153 
154  // create the node
155  Node* between = (Node*)TM_ALLOC(sizeof(Node));
156  between->m_val = val;
157  between->m_prev = before;
158  between->m_next = after;
159 
160  TM_WRITE(before->m_next, between);
161  TM_WRITE(after->m_prev, between);
162  }
163 }
164 
165 // search for a value
167 bool DList::lookup(int val TM_ARG) const
168 {
169  bool found = false;
170 
171  const Node* curr(head);
172  curr = TM_READ(curr->m_next);
173  while (curr != NULL) {
174  if (TM_READ(curr->m_val) >= val)
175  break;
176  curr = TM_READ(curr->m_next);
177  }
178  found = ((curr != NULL) && (TM_READ(curr->m_val) == val));
179 
180  return found;
181 }
182 
183 // remove a node if its value == val
185 void DList::remove(int val TM_ARG)
186 {
187  // find the node whose val matches the request
188  const Node* prev(head);
189  const Node* curr(TM_READ(prev->m_next));
190 
191  while (curr != NULL) {
192  // if we find the node, disconnect it and end the search
193  if (TM_READ(curr->m_val) == val) {
194  Node* before = const_cast<Node*>(prev);
195  Node* after(TM_READ(curr->m_next));
196  TM_WRITE(before->m_next, after);
197  TM_WRITE(after->m_prev, before);
198 
199  // delete curr...
200  TM_FREE(const_cast<Node*>(curr));
201  break;
202  }
203  else if (TM_READ(curr->m_val) > val) {
204  // this means the search failed
205  break;
206  }
207 
208  prev = curr;
209  curr = TM_READ(prev->m_next);
210  }
211 
212 }
213 
216 {
217  // forward traversal
218  const Node* prev(head);
219  Node* curr(TM_READ(prev->m_next));
220  while (curr != tail) {
221  // increment curr
222  TM_WRITE(curr->m_val, 1 + TM_READ(curr->m_val));
223  curr = TM_READ(curr->m_next);
224  }
225 }
226 
229 {
230  // backward traversal
231  const Node* prev(tail);
232  Node* curr(TM_READ(prev->m_prev));
233  while (curr != head) {
234  // increment curr
235  TM_WRITE(curr->m_val, 1 + TM_READ(curr->m_val));
236  curr = TM_READ(curr->m_prev);
237  }
238 }
239 
240 // increment every seqth element, starting with start, moving forward
243 {
244  int sum = 0;
245  // forward traversal to element # start
246  const Node* prev(head);
247  const Node* curr(TM_READ(prev->m_next));
248  for (int i = 0; i < start; i++) {
249  curr = TM_READ(curr->m_next);
250  }
251  // now do the remainder of the traversal, incrementing every seqth
252  // element
253  int ctr = seq;
254  while (curr != tail) {
255  // increment the seqth element
256  if (ctr == seq) {
257  ctr = 0;
258  Node* cw = const_cast<Node*>(curr);
259  TM_WRITE(cw->m_val, 1 + TM_READ(cw->m_val));
260  curr = cw;
261  }
262  ctr++;
263  sum += TM_READ(curr->m_val);
264  curr = TM_READ(curr->m_next);
265  }
266 }
267 
268 // increment every element, starting with start, moving backward
271 {
272  int sum = 0;
273  // backward traversal to element # start
274  const Node* prev(tail);
275  const Node* curr(TM_READ(prev->m_prev));
276  for (int i = 0; i < start; i++) {
277  curr = TM_READ(curr->m_prev);
278  }
279  // now do the remainder of the traversal, incrementing every seqth
280  // element
281  int ctr = seq;
282  while (curr != head) {
283  // increment the seqth element
284  if (ctr == seq) {
285  ctr = 0;
286  Node* cw = const_cast<Node*>(curr);
287  TM_WRITE(cw->m_val, 1 + TM_READ(cw->m_val));
288  curr = cw;
289  }
290  ctr++;
291  sum += TM_READ(curr->m_val);
292  curr = TM_READ(curr->m_prev);
293  }
294 }
295 
296 // increment every seqth element, starting with start, moving forward
298 void DList::increment_chunk(int chunk_num, int chunk_size TM_ARG)
299 {
300  int startpoint = chunk_num * chunk_size;
301 
302  int sum = 0;
303  Node* chunk_start(NULL);
304  int ctr = 0;
305 
306  // forward traversal to compute sum and to find chunk_start
307  const Node* prev(head);
308  const Node* curr(TM_READ(prev->m_next));
309  while (curr != tail) {
310  // if this is the start of our chunk, save the pointer
311  if (ctr++ == startpoint)
312  chunk_start = const_cast<Node*>(curr);
313  // add this value to the sum
314  sum += TM_READ(curr->m_val);
315  // move to next node
316  curr = TM_READ(curr->m_next);
317  }
318  // OK, at this point we should have the ID of the chunk we're going to
319  // work on. increment everything in our chunk
320  if (chunk_start != NULL) {
321  // avoid TLS overhead on every loop iteration:
322  Node* wr(chunk_start);
323  // increment /chunk_size/ elements
324  for (int i = 0; i < chunk_size; i++) {
325  // don't increment if we reach the tail
326  if (chunk_start == tail)
327  break;
328  // increment, move to next
329  TM_WRITE(wr->m_val, 1 + TM_READ(wr->m_val));
330  wr = TM_READ(wr->m_next);
331  }
332  }
333 }
334 
335 #endif // DLIST_HPP__
#define TM_CALLABLE
Definition: cxxtm.hpp:32
#define TM_ARG_ALONE
Definition: cxxtm.hpp:41
#define TM_WRITE(x, y)
Definition: cxxtm.hpp:46
static void * start(jsw_avltrav_t *trav, jsw_avltree_t *tree, long dir)
Definition: avltree.c:681
Node(int val)
Definition: DList.hpp:28
TM_CALLABLE void remove(int val TM_ARG)
Definition: DList.hpp:185
TM_CALLABLE void increment_forward_pattern(int start, int seq TM_ARG)
Definition: DList.hpp:242
static const int cw
Definition: point.hpp:23
#define TM_ARG
Definition: cxxtm.hpp:40
Node * head
Definition: DList.hpp:34
Definition: DList.hpp:21
TM_CALLABLE void increment_backward_pattern(int start, int seq TM_ARG)
Definition: DList.hpp:270
TM_CALLABLE bool lookup(int val TM_ARG) const
Definition: DList.hpp:167
#define TM_READ(x)
Definition: cxxtm.hpp:45
Definition: DList.hpp:18
TM_CALLABLE void increment_backward(TM_ARG_ALONE)
Definition: DList.hpp:228
Node * tail
Definition: DList.hpp:35
DList()
Definition: DList.hpp:78
TM_CALLABLE void increment_chunk(int chunk_num, int chunk_size TM_ARG)
Definition: DList.hpp:298
#define TM_ALLOC
Definition: library.hpp:294
Node * m_next
Definition: DList.hpp:25
struct @18 p
bool isSane() const
Definition: DList.hpp:85
TM_CALLABLE void insert(int val TM_ARG)
Definition: DList.hpp:135
Node * m_prev
Definition: DList.hpp:24
#define TM_FREE
Definition: library.hpp:295
TM_CALLABLE void increment_forward(TM_ARG_ALONE)
Definition: DList.hpp:215
int m_val
Definition: DList.hpp:23