LinkedList.hpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007 #ifndef LINKEDLIST_HPP
00008 #define LINKEDLIST_HPP
00009
00010 #include "Benzene.hpp"
00011 #include "SafeBool.hpp"
00012 #include <cassert>
00013 #include <iostream>
00014 #include <boost/utility.hpp>
00015
00016 _BEGIN_BENZENE_NAMESPACE_
00017
00018
00019
00020
00021 template<typename T>
00022 class ListNode
00023 {
00024 public:
00025 ListNode();
00026
00027 ListNode(const T& data);
00028
00029 bool AddChild(ListNode<T>* child, ListNode<T>* successor) volatile;
00030
00031 void Delete() volatile;
00032
00033 private:
00034 T m_data;
00035
00036 bool m_locked;
00037
00038 bool m_deleted;
00039
00040 ListNode<T>* m_next;
00041
00042 ListNode<T>* m_dead;
00043
00044 struct ScopedLock
00045 {
00046 volatile ListNode<T>& m_obj;
00047
00048 ScopedLock(volatile ListNode<T>& obj)
00049 : m_obj(obj)
00050 {
00051 while (!__sync_bool_compare_and_swap(&m_obj.m_locked, false, true))
00052 ;
00053 }
00054 ~ScopedLock()
00055 {
00056 m_obj.m_locked = false;
00057 }
00058 };
00059
00060 ListNode<T>* GetNext() volatile;
00061
00062 void TryFixLink(ListNode<T>* node) volatile;
00063
00064 template<typename U> friend class Pool;
00065
00066 template<typename U> friend class ListIterator;
00067
00068 template<typename U> friend class LinkedList;
00069 };
00070
00071
00072 template<typename T>
00073 ListNode<T>::ListNode()
00074 : m_locked(false),
00075 m_deleted(false),
00076 m_next(0),
00077 m_dead(0)
00078 {
00079 }
00080
00081 template<typename T>
00082 ListNode<T>::ListNode(const T& data)
00083 : m_data(data),
00084 m_locked(false),
00085 m_deleted(false),
00086 m_next(0),
00087 m_dead(0)
00088 {
00089 }
00090
00091
00092 template<typename T>
00093 bool ListNode<T>::AddChild(ListNode<T>* child, ListNode<T>* successor) volatile
00094 {
00095 ScopedLock lock(*this);
00096 if (!m_deleted && m_next == successor)
00097 {
00098 child->m_next = m_next;
00099 m_next = child;
00100 return true;
00101 }
00102 return false;
00103 }
00104
00105
00106
00107
00108 template<typename T>
00109 void ListNode<T>::Delete() volatile
00110 {
00111 ScopedLock lock(*this);
00112 m_deleted = true;
00113 }
00114
00115
00116 template<typename T>
00117 void ListNode<T>::TryFixLink(ListNode<T>* node) volatile
00118 {
00119 ScopedLock lock(*this);
00120 if (m_next == node)
00121 m_next = node->m_next;
00122 }
00123
00124
00125
00126
00127 template<typename T>
00128 ListNode<T>* ListNode<T>::GetNext() volatile
00129 {
00130 ListNode<T>* node = m_next;
00131 while ((node != 0) && node->m_deleted)
00132 {
00133 TryFixLink(node);
00134 node = node->m_next;
00135 }
00136 return node;
00137 }
00138
00139
00140
00141
00142
00143
00144 template<typename T>
00145 class Pool : boost::noncopyable
00146 {
00147 public:
00148
00149 static const std::size_t CHUNK_SIZE = 1 << 24;
00150
00151 Pool();
00152
00153 ~Pool();
00154
00155 std::size_t Allocated() const;
00156
00157 std::size_t ChunkSize() const;
00158
00159
00160 ListNode<T>* Get() volatile;
00161
00162
00163 void AddToDeadList(ListNode<T>* node) volatile;
00164
00165
00166 void Put(ListNode<T>* node);
00167
00168
00169 void RaiseTheDead();
00170
00171 private:
00172 ListNode<T>* m_head;
00173
00174 ListNode<T>* m_dead;
00175
00176 bool m_lockedHead;
00177
00178 bool m_lockedDead;
00179
00180 std::size_t m_allocated;
00181
00182 std::size_t m_chunkSize;
00183
00184 std::vector<ListNode<T>* > m_chunks;
00185
00186 void Allocate();
00187 };
00188
00189 template<typename T>
00190 Pool<T>::Pool()
00191 : m_head(0),
00192 m_dead(0),
00193 m_lockedHead(false),
00194 m_lockedDead(false),
00195 m_allocated(0),
00196 m_chunkSize(CHUNK_SIZE)
00197 {
00198 Allocate();
00199 }
00200
00201 template<typename T>
00202 Pool<T>::~Pool()
00203 {
00204 for (std::size_t i = 0; i < m_chunks.size(); ++i)
00205 delete [] m_chunks[i];
00206 }
00207
00208 template<typename T>
00209 std::size_t Pool<T>::Allocated() const
00210 {
00211 return m_allocated;
00212 }
00213
00214 template<typename T>
00215 std::size_t Pool<T>::ChunkSize() const
00216 {
00217 return m_chunkSize;
00218 }
00219
00220 template<typename T>
00221 void Pool<T>::Allocate()
00222 {
00223 assert(m_head == 0);
00224 std::size_t num = m_chunkSize / sizeof(ListNode<T>);
00225 ListNode<T>* data = new ListNode<T>[num];
00226 m_chunks.push_back(data);
00227 for (std::size_t i = 0; i < num - 1; ++i)
00228 data[i].m_next = &data[i + 1];
00229 data[num - 1].m_next = 0;
00230 m_head = data;
00231 m_allocated += num * sizeof(ListNode<T>);
00232 }
00233
00234 template<typename T>
00235 ListNode<T>* Pool<T>::Get() volatile
00236 {
00237 while (!__sync_bool_compare_and_swap(&m_lockedHead, false, true));
00238 if (m_head == 0)
00239 {
00240
00241 Pool<T>& ref = const_cast<Pool<T>&>(*this);
00242 ref.Allocate();
00243 }
00244 ListNode<T>* ret = m_head;
00245 m_head = m_head->m_next;
00246 m_lockedHead = false;
00247 return ret;
00248 }
00249
00250 template<typename T>
00251 void Pool<T>::AddToDeadList(ListNode<T>* node) volatile
00252 {
00253 while (!__sync_bool_compare_and_swap(&m_lockedDead, false, true));
00254 node->m_dead = m_dead;
00255 m_dead = node;
00256 m_lockedDead = false;
00257 }
00258
00259 template<typename T>
00260 void Pool<T>::RaiseTheDead()
00261 {
00262 ListNode<T>* node = m_dead;
00263 while (node)
00264 {
00265 ListNode<T>* next = node->m_dead;
00266 node->m_dead = 0;
00267 Put(node);
00268 node = next;
00269 }
00270 m_dead = 0;
00271 }
00272
00273 template<typename T>
00274 void Pool<T>::Put(ListNode<T>* node)
00275 {
00276 node->m_next = m_head;
00277 m_head = node;
00278 }
00279
00280
00281
00282
00283
00284
00285 template<typename T>
00286 class LinkedList
00287 {
00288 public:
00289 LinkedList(Pool<T>& pool);
00290
00291 LinkedList(const LinkedList<T>& other);
00292
00293 virtual ~LinkedList();
00294
00295 bool Empty() const;
00296
00297 void Add(const T& data);
00298
00299 void Remove(const T& data);
00300
00301 void Clear();
00302
00303 void operator=(const LinkedList<T>& other);
00304
00305 bool operator==(const LinkedList<T>& other) const;
00306
00307 private:
00308 template <typename U> friend class ListIterator;
00309
00310 Pool<T>& m_pool;
00311
00312 mutable ListNode<T> m_head;
00313
00314 void CopyList(const LinkedList<T>& other);
00315 };
00316
00317 template<typename T>
00318 LinkedList<T>::LinkedList(Pool<T>& pool)
00319 : m_pool(pool)
00320 {
00321 m_head.m_next = 0;
00322 }
00323
00324 template<typename T>
00325 LinkedList<T>::LinkedList(const LinkedList<T>& other)
00326 : m_pool(other.m_pool)
00327 {
00328 CopyList(other);
00329 }
00330
00331 template<typename T>
00332 LinkedList<T>::~LinkedList()
00333 {
00334 }
00335
00336 template<typename T>
00337 bool LinkedList<T>::Empty() const
00338 {
00339 return m_head.GetNext() == 0;
00340 }
00341
00342 template<typename T>
00343 void LinkedList<T>::Clear()
00344 {
00345 ListNode<T>* node = m_head.GetNext();
00346 while (node != 0)
00347 {
00348 ListNode<T>* next = node.GetNext();
00349 m_pool.Put(node);
00350 node = next;
00351 }
00352 m_head.m_next = 0;
00353 }
00354
00355 template<typename T>
00356 void LinkedList<T>::CopyList(const LinkedList<T>& other)
00357 {
00358 assert(m_head.m_next == 0);
00359 ListNode<T>* them = other.m_head.GetNext();
00360 ListNode<T>* mine = m_head;
00361 while (them != 0)
00362 {
00363 ListNode<T>* child = new (m_pool.Get()) ListNode<T>(them->m_data);
00364 mine->AddChild(child);
00365 mine = mine->GetNext();
00366 them = them->GetNext();
00367 }
00368 }
00369
00370 template<typename T>
00371 void LinkedList<T>::Add(const T& data)
00372 {
00373 ListNode<T>* node = 0;
00374 while (true)
00375 {
00376 ListNode<T>* current = &m_head;
00377 ListNode<T>* next = current->GetNext();
00378 while ((next != 0) && next->m_data < data)
00379 {
00380 current = next;
00381 next = current->GetNext();
00382 }
00383
00384
00385
00386 if ((next != 0) && next->m_data == data)
00387 break;
00388
00389
00390 if (node == 0)
00391 node = new (m_pool.Get()) ListNode<T>(data);
00392 if (current->AddChild(node, next))
00393 break;
00394 }
00395 }
00396
00397 template<typename T>
00398 void LinkedList<T>::Remove(const T& data)
00399 {
00400 ListNode<T>* parent = &m_head;
00401 ListNode<T>* next = parent->GetNext();
00402 while ((next != 0) && next->m_data != data)
00403 {
00404 parent = next;
00405 next = parent->GetNext();
00406 }
00407 if (next != 0)
00408 {
00409 next->Delete();
00410 parent->TryFixLink(next);
00411 m_pool.AddToDeadList(next);
00412 }
00413 }
00414
00415 template<typename T>
00416 void LinkedList<T>::operator=(const LinkedList<T>& other)
00417 {
00418 Clear();
00419 CopyList(other);
00420 }
00421
00422 template<typename T>
00423 bool LinkedList<T>::operator==(const LinkedList<T>& other) const
00424 {
00425 ListNode<T>* mine = m_head.GetNext();
00426 ListNode<T>* them = other.m_head.GetNext();
00427 while ((mine != 0) && (them != 0))
00428 {
00429 if (mine->m_data != them->m_data)
00430 return false;
00431 mine = mine->GetNext();
00432 them = them->GetNext();
00433 }
00434 return (mine != 0) == (them != 0);
00435 }
00436
00437
00438
00439
00440 template<typename T>
00441 class ListIterator : public SafeBool<ListIterator<T> >
00442 {
00443 public:
00444 ListIterator(LinkedList<T>& lst);
00445
00446 T& operator*();
00447
00448 ListIterator<T>& operator++();
00449
00450 bool boolean_test() const;
00451
00452 private:
00453 ListNode<T>* m_current;
00454
00455 template <typename U> friend class LinkedList;
00456 };
00457
00458 template<typename T>
00459 ListIterator<T>::ListIterator(LinkedList<T>& lst)
00460 : m_current(lst.m_head.GetNext())
00461 {
00462 }
00463
00464 template<typename T>
00465 T& ListIterator<T>::operator*()
00466 {
00467 return m_current->m_data;
00468 }
00469
00470 template<typename T>
00471 ListIterator<T>& ListIterator<T>::operator++()
00472 {
00473 m_current = m_current->GetNext();
00474 return *this;
00475 }
00476
00477 template<typename T>
00478 bool ListIterator<T>::boolean_test() const
00479 {
00480 return m_current != 0;
00481 }
00482
00483
00484
00485 _END_BENZENE_NAMESPACE_
00486
00487 #endif // LINKEDLIST_HPP