BWAPI
|
00001 // Copyright (c) 2003,2004,2007-2009 INRIA Sophia-Antipolis (France). 00002 // All rights reserved. 00003 // 00004 // This file is part of CGAL (www.cgal.org); you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public License as 00006 // published by the Free Software Foundation; version 2.1 of the License. 00007 // See the file LICENSE.LGPL distributed with CGAL. 00008 // 00009 // Licensees holding a valid commercial license may use this file in 00010 // accordance with the commercial license agreement provided with the software. 00011 // 00012 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00013 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00014 // 00015 // $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.5-branch/STL_Extension/include/CGAL/Compact_container.h $ 00016 // $Id: Compact_container.h 48759 2009-04-10 21:55:24Z spion $ 00017 // 00018 // Author(s) : Sylvain Pion 00019 00020 #ifndef CGAL_COMPACT_CONTAINER_H 00021 #define CGAL_COMPACT_CONTAINER_H 00022 00023 #include <CGAL/basic.h> 00024 #include <CGAL/Default.h> 00025 00026 #include <iterator> 00027 #include <algorithm> 00028 #include <vector> 00029 00030 #include <CGAL/memory.h> 00031 #include <CGAL/iterator.h> 00032 00033 #include <boost/mpl/if.hpp> 00034 00035 // An STL like container with the following properties : 00036 // - to achieve compactness, it requires access to a pointer stored in T, 00037 // specified by a traits. This pointer is supposed to be 4 bytes aligned 00038 // when the object is alive, otherwise, the container uses the 2 least 00039 // significant bits to store information in the pointer. 00040 // - Ts are allocated in arrays of increasing size, which are linked together 00041 // by their first and last element. 00042 // - the iterator looks at the famous 2 bits to know if it has to deal with 00043 // a free/used/boundary element. 00044 00045 // TODO : 00046 // - Add .reserve() and .resize() (and proper copy of capacity_). 00047 // - Add preconditions in input that real pointers need to have clean bits. 00048 // Also for the allocated memory alignment, and sizeof(). 00049 // - Do a benchmark before/after. 00050 // - Check the end result with Valgrind. 00051 // - The bit squatting mecanism will be reused for the conflict flag, maybe 00052 // it could be put out of the class. 00053 00054 // TODO low priority : 00055 // - rebind<> the allocator 00056 // - Exception safety guarantees 00057 // - Thread safety guarantees 00058 // - std requirements on iterators says all defined operations are constant 00059 // time amortized (it's not true here, maybe it could be with some work...) 00060 // - all this is expected especially when there are not so many free objects 00061 // compared to the allocated elements. 00062 // - Should block_size be selectable/hintable by .reserve() ? 00063 // - would be nice to have a temporary_free_list (still active elements, but 00064 // which are going to be freed soon). Probably it prevents compactness. 00065 // - eventually something to copy this data structure, providing a way to 00066 // update the pointers (give access to a hash_map, at least a function that 00067 // converts an old pointer to the new one ?). Actually it doesn't have to 00068 // be stuck to a particular DS, because for a list it's useful too... 00069 // - Currently, end() can be invalidated on insert() if a new block is added. 00070 // It would be nice to fix this. We could insert the new block at the 00071 // beginning instead ? That would drop the property that iterator order 00072 // is preserved. Maybe it's not a problem if end() is not preserved, after 00073 // all nothing is going to dereference it, it's just for comparing with 00074 // end() that it can be a problem. 00075 // Another way would be to have end() point to the end of an always 00076 // empty block (containing no usable element), and insert new blocks just 00077 // before this one. 00078 // Instead of having the blocks linked between them, the start/end pointers 00079 // could point back to the container, so that we can do more interesting 00080 // things (e.g. freeing empty blocks automatically) ? 00081 // - Submission to Boost. 00082 00083 CGAL_BEGIN_NAMESPACE 00084 00085 // The following base class can be used to easily add a squattable pointer 00086 // to a class (maybe you loose a bit of compactness though). 00087 // TODO : Shouldn't adding these bits be done automatically and transparently, 00088 // based on the traits class info ? 00089 class Compact_container_base 00090 { 00091 void * p; 00092 public: 00093 Compact_container_base() 00094 : p(NULL) {} 00095 void * for_compact_container() const { return p; } 00096 void * & for_compact_container() { return p; } 00097 }; 00098 00099 // The traits class describes the way to access the pointer. 00100 // It can be specialized. 00101 template < class T > 00102 struct Compact_container_traits { 00103 static void * pointer(const T &t) { return t.for_compact_container(); } 00104 static void * & pointer(T &t) { return t.for_compact_container(); } 00105 }; 00106 00107 namespace CGALi { 00108 template < class DSC, bool Const > 00109 class CC_iterator; 00110 } 00111 00112 template < class T, class Allocator_ = Default > 00113 class Compact_container 00114 { 00115 typedef Allocator_ Al; 00116 typedef typename Default::Get< Al, CGAL_ALLOCATOR(T) >::type Allocator; 00117 typedef Compact_container <T, Al> Self; 00118 typedef Compact_container_traits <T> Traits; 00119 public: 00120 typedef T value_type; 00121 typedef Allocator allocator_type; 00122 typedef typename Allocator::reference reference; 00123 typedef typename Allocator::const_reference const_reference; 00124 typedef typename Allocator::pointer pointer; 00125 typedef typename Allocator::const_pointer const_pointer; 00126 typedef typename Allocator::size_type size_type; 00127 typedef typename Allocator::difference_type difference_type; 00128 typedef CGALi::CC_iterator<Self, false> iterator; 00129 typedef CGALi::CC_iterator<Self, true> const_iterator; 00130 typedef std::reverse_iterator<iterator> reverse_iterator; 00131 typedef std::reverse_iterator<const_iterator> const_reverse_iterator; 00132 00133 friend class CGALi::CC_iterator<Self, false>; 00134 friend class CGALi::CC_iterator<Self, true>; 00135 00136 explicit Compact_container(const Allocator &a = Allocator()) 00137 : alloc(a) 00138 { 00139 init(); 00140 } 00141 00142 template < class InputIterator > 00143 Compact_container(InputIterator first, InputIterator last, 00144 const Allocator & a = Allocator()) 00145 : alloc(a) 00146 { 00147 init(); 00148 std::copy(first, last, CGAL::inserter(*this)); 00149 } 00150 00151 // The copy constructor and assignment operator preserve the iterator order 00152 Compact_container(const Compact_container &c) 00153 : alloc(c.get_allocator()) 00154 { 00155 init(); 00156 block_size = c.block_size; 00157 std::copy(c.begin(), c.end(), CGAL::inserter(*this)); 00158 } 00159 00160 Compact_container & operator=(const Compact_container &c) 00161 { 00162 if (&c != this) { 00163 Self tmp(c); 00164 swap(tmp); 00165 } 00166 return *this; 00167 } 00168 00169 ~Compact_container() 00170 { 00171 clear(); 00172 } 00173 00174 void swap(Self &c) 00175 { 00176 std::swap(alloc, c.alloc); 00177 std::swap(capacity_, c.capacity_); 00178 std::swap(size_, c.size_); 00179 std::swap(block_size, c.block_size); 00180 std::swap(first_item, c.first_item); 00181 std::swap(last_item, c.last_item); 00182 std::swap(free_list, c.free_list); 00183 all_items.swap(c.all_items); 00184 } 00185 00186 iterator begin() { return iterator(first_item, 0, 0); } 00187 iterator end() { return iterator(last_item, 0); } 00188 00189 const_iterator begin() const { return const_iterator(first_item, 0, 0); } 00190 const_iterator end() const { return const_iterator(last_item, 0); } 00191 00192 reverse_iterator rbegin() { return reverse_iterator(end()); } 00193 reverse_iterator rend() { return reverse_iterator(begin()); } 00194 00195 const_reverse_iterator 00196 rbegin() const { return const_reverse_iterator(end()); } 00197 const_reverse_iterator 00198 rend() const { return const_reverse_iterator(begin()); } 00199 00200 // Boost.Intrusive interface 00201 iterator iterator_to(reference value) const { 00202 return iterator(&value, 0); 00203 } 00204 const_iterator iterator_to(const_reference value) const { 00205 return const_iterator(&value, 0); 00206 } 00207 static iterator s_iterator_to(reference value) { 00208 return iterator(&value, 0); 00209 } 00210 static const_iterator s_iterator_to(const_reference value) { 00211 return const_iterator(&value, 0); 00212 } 00213 00214 // Special insert methods that construct the objects in place 00215 // (just forward the arguments to the constructor, to optimize a copy). 00216 #ifndef CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES 00217 template < typename... Args > 00218 iterator 00219 emplace(const Args&... args) 00220 { 00221 if (free_list == NULL) 00222 allocate_new_block(); 00223 00224 pointer ret = free_list; 00225 free_list = clean_pointee(ret); 00226 new (ret) value_type(args...); 00227 CGAL_assertion(type(ret) == USED); 00228 ++size_; 00229 return iterator(ret, 0); 00230 } 00231 #else 00232 // inserts a default constructed item. 00233 iterator emplace() 00234 { 00235 if (free_list == NULL) 00236 allocate_new_block(); 00237 00238 pointer ret = free_list; 00239 free_list = clean_pointee(ret); 00240 new (ret) value_type(); 00241 CGAL_assertion(type(ret) == USED); 00242 ++size_; 00243 return iterator(ret, 0); 00244 } 00245 00246 template < typename T1 > 00247 iterator 00248 emplace(const T1 &t1) 00249 { 00250 if (free_list == NULL) 00251 allocate_new_block(); 00252 00253 pointer ret = free_list; 00254 free_list = clean_pointee(ret); 00255 new (ret) value_type(t1); 00256 CGAL_assertion(type(ret) == USED); 00257 ++size_; 00258 return iterator(ret, 0); 00259 } 00260 00261 template < typename T1, typename T2 > 00262 iterator 00263 emplace(const T1 &t1, const T2 &t2) 00264 { 00265 if (free_list == NULL) 00266 allocate_new_block(); 00267 00268 pointer ret = free_list; 00269 free_list = clean_pointee(ret); 00270 new (ret) value_type(t1, t2); 00271 CGAL_assertion(type(ret) == USED); 00272 ++size_; 00273 return iterator(ret, 0); 00274 } 00275 00276 template < typename T1, typename T2, typename T3 > 00277 iterator 00278 emplace(const T1 &t1, const T2 &t2, const T3 &t3) 00279 { 00280 if (free_list == NULL) 00281 allocate_new_block(); 00282 00283 pointer ret = free_list; 00284 free_list = clean_pointee(ret); 00285 new (ret) value_type(t1, t2, t3); 00286 CGAL_assertion(type(ret) == USED); 00287 ++size_; 00288 return iterator(ret, 0); 00289 } 00290 00291 template < typename T1, typename T2, typename T3, typename T4 > 00292 iterator 00293 emplace(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) 00294 { 00295 if (free_list == NULL) 00296 allocate_new_block(); 00297 00298 pointer ret = free_list; 00299 free_list = clean_pointee(ret); 00300 new (ret) value_type(t1, t2, t3, t4); 00301 CGAL_assertion(type(ret) == USED); 00302 ++size_; 00303 return iterator(ret, 0); 00304 } 00305 00306 template < typename T1, typename T2, typename T3, typename T4, typename T5 > 00307 iterator 00308 emplace(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, 00309 const T5 &t5) 00310 { 00311 if (free_list == NULL) 00312 allocate_new_block(); 00313 00314 pointer ret = free_list; 00315 free_list = clean_pointee(ret); 00316 new (ret) value_type(t1, t2, t3, t4, t5); 00317 CGAL_assertion(type(ret) == USED); 00318 ++size_; 00319 return iterator(ret, 0); 00320 } 00321 00322 template < typename T1, typename T2, typename T3, typename T4, 00323 typename T5, typename T6 > 00324 iterator 00325 emplace(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, 00326 const T5 &t5, const T6 &t6) 00327 { 00328 if (free_list == NULL) 00329 allocate_new_block(); 00330 00331 pointer ret = free_list; 00332 free_list = clean_pointee(ret); 00333 new (ret) value_type(t1, t2, t3, t4, t5, t6); 00334 CGAL_assertion(type(ret) == USED); 00335 ++size_; 00336 return iterator(ret, 0); 00337 } 00338 00339 template < typename T1, typename T2, typename T3, typename T4, 00340 typename T5, typename T6, typename T7 > 00341 iterator 00342 emplace(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, 00343 const T5 &t5, const T6 &t6, const T7 &t7) 00344 { 00345 if (free_list == NULL) 00346 allocate_new_block(); 00347 00348 pointer ret = free_list; 00349 free_list = clean_pointee(ret); 00350 new (ret) value_type(t1, t2, t3, t4, t5, t6, t7); 00351 CGAL_assertion(type(ret) == USED); 00352 ++size_; 00353 return iterator(ret, 0); 00354 } 00355 00356 template < typename T1, typename T2, typename T3, typename T4, 00357 typename T5, typename T6, typename T7, typename T8 > 00358 iterator 00359 emplace(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, 00360 const T5 &t5, const T6 &t6, const T7 &t7, const T8 &t8) 00361 { 00362 if (free_list == NULL) 00363 allocate_new_block(); 00364 00365 pointer ret = free_list; 00366 free_list = clean_pointee(ret); 00367 new (ret) value_type(t1, t2, t3, t4, t5, t6, t7, t8); 00368 CGAL_assertion(type(ret) == USED); 00369 ++size_; 00370 return iterator(ret, 0); 00371 } 00372 #endif // CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES 00373 00374 iterator insert(const T &t) 00375 { 00376 if (free_list == NULL) 00377 allocate_new_block(); 00378 00379 pointer ret = free_list; 00380 free_list = clean_pointee(ret); 00381 alloc.construct(ret, t); 00382 CGAL_assertion(type(ret) == USED); 00383 ++size_; 00384 return iterator(ret, 0); 00385 } 00386 00387 template < class InputIterator > 00388 void insert(InputIterator first, InputIterator last) 00389 { 00390 for (; first != last; ++first) 00391 insert(*first); 00392 } 00393 00394 template < class InputIterator > 00395 void assign(InputIterator first, InputIterator last) 00396 { 00397 clear(); // erase(begin(), end()); // ? 00398 insert(first, last); 00399 } 00400 00401 void erase(iterator x) 00402 { 00403 CGAL_precondition(type(&*x) == USED); 00404 alloc.destroy(&*x); 00405 put_on_free_list(&*x); 00406 --size_; 00407 } 00408 00409 void erase(iterator first, iterator last) { 00410 for (; first != last; ++first) 00411 erase(first); 00412 } 00413 00414 void clear(); 00415 00416 // Merge the content of d into *this. d gets cleared. 00417 // The complexity is O(size(free list = capacity-size)). 00418 void merge(Self &d); 00419 00420 size_type size() const 00421 { 00422 CGAL_expensive_assertion(size_ == 00423 (size_type) std::distance(begin(), end())); 00424 return size_; 00425 } 00426 00427 size_type max_size() const 00428 { 00429 return alloc.max_size(); 00430 } 00431 00432 size_type capacity() const 00433 { 00434 return capacity_; 00435 } 00436 00437 void reserve(size_type n); // TODO 00438 00439 // void resize(size_type sz, T c = T()); // TODO makes sense ??? 00440 00441 bool empty() const 00442 { 00443 return size_ == 0; 00444 } 00445 00446 allocator_type get_allocator() const 00447 { 00448 return alloc; 00449 } 00450 00451 private: 00452 00453 void allocate_new_block(); 00454 00455 void put_on_free_list(pointer x) 00456 { 00457 set_type(x, free_list, FREE); 00458 free_list = x; 00459 } 00460 00461 // Definition of the bit squatting : 00462 // ================================= 00463 // ptr is composed of a pointer part and the last 2 bits. 00464 // Here is the meaning of each of the 8 cases. 00465 // 00466 // value of the last 2 bits as "Type" 00467 // pointer part 0 1 2 3 00468 // NULL user elt unused free_list end start/end 00469 // != NULL user elt block boundary free elt unused 00470 // 00471 // meaning of ptr : user stuff next/prev block free_list unused 00472 00473 enum Type { USED = 0, BLOCK_BOUNDARY = 1, FREE = 2, START_END = 3 }; 00474 00475 // The bit squatting is implemented by casting pointers to (char *), then 00476 // subtracting to NULL, doing bit manipulations on the resulting integer, 00477 // and converting back. 00478 00479 static char * clean_pointer(char * p) 00480 { 00481 return ((p - (char *) NULL) & ~ (std::ptrdiff_t) START_END) + (char *) NULL; 00482 } 00483 00484 // Returns the pointee, cleaned up from the squatted bits. 00485 static pointer clean_pointee(const_pointer ptr) 00486 { 00487 return (pointer) clean_pointer((char *) Traits::pointer(*ptr)); 00488 } 00489 00490 // Get the type of the pointee. 00491 static Type type(const_pointer ptr) 00492 { 00493 char * p = (char *) Traits::pointer(*ptr); 00494 return (Type) (p - clean_pointer(p)); 00495 } 00496 00497 // Sets the pointer part and the type of the pointee. 00498 static void set_type(pointer ptr, void * p, Type t) 00499 { 00500 CGAL_precondition(0 <= t && t < 4); 00501 Traits::pointer(*ptr) = (void *) ((clean_pointer((char *) p)) + (int) t); 00502 } 00503 00504 // We store a vector of pointers to all allocated blocks and their sizes. 00505 // Knowing all pointers, we don't have to walk to the end of a block to reach 00506 // the pointer to the next block. 00507 // Knowing the sizes allows to deallocate() without having to compute the size 00508 // by walking through the block till its end. 00509 // This opens up the possibility for the compiler to optimize the clear() 00510 // function considerably when has_trivial_destructor<T>. 00511 typedef std::vector<std::pair<pointer, size_type> > All_items; 00512 00513 void init() 00514 { 00515 block_size = 14; 00516 capacity_ = 0; 00517 size_ = 0; 00518 free_list = NULL; 00519 first_item = NULL; 00520 last_item = NULL; 00521 all_items = All_items(); 00522 } 00523 00524 allocator_type alloc; 00525 size_type capacity_; 00526 size_type size_; 00527 size_type block_size; 00528 pointer free_list; 00529 pointer first_item; 00530 pointer last_item; 00531 All_items all_items; 00532 }; 00533 00534 template < class T, class Allocator > 00535 void Compact_container<T, Allocator>::merge(Self &d) 00536 { 00537 CGAL_precondition(&d != this); 00538 00539 // Allocators must be "compatible" : 00540 CGAL_precondition(get_allocator() == d.get_allocator()); 00541 00542 // Concatenate the free_lists. 00543 if (free_list == NULL) { 00544 free_list = d.free_list; 00545 } else if (d.free_list != NULL) { 00546 pointer p = free_list; 00547 while (clean_pointee(p) != NULL) 00548 p = clean_pointee(p); 00549 set_type(p, d.free_list, FREE); 00550 } 00551 // Concatenate the blocks. 00552 if (last_item == NULL) { // empty... 00553 first_item = d.first_item; 00554 last_item = d.last_item; 00555 } else if (d.last_item != NULL) { 00556 set_type(last_item, d.first_item, BLOCK_BOUNDARY); 00557 set_type(d.first_item, last_item, BLOCK_BOUNDARY); 00558 last_item = d.last_item; 00559 } 00560 // Add the sizes. 00561 size_ += d.size_; 00562 // Add the capacities. 00563 capacity_ += d.capacity_; 00564 // It seems reasonnable to take the max of the block sizes. 00565 block_size = (std::max)(block_size, d.block_size); 00566 // Clear d. 00567 d.init(); 00568 } 00569 00570 template < class T, class Allocator > 00571 void Compact_container<T, Allocator>::clear() 00572 { 00573 for (typename All_items::iterator it = all_items.begin(), end = all_items.end(); 00574 it != end; ++it) { 00575 pointer p = it->first; 00576 size_type s = it->second; 00577 for (pointer pp = p + 1; pp != p + s - 1; ++pp) { 00578 if (type(pp) == USED) 00579 alloc.destroy(pp); 00580 } 00581 alloc.deallocate(p, s); 00582 } 00583 init(); 00584 } 00585 00586 template < class T, class Allocator > 00587 void Compact_container<T, Allocator>::allocate_new_block() 00588 { 00589 pointer new_block = alloc.allocate(block_size + 2); 00590 all_items.push_back(std::make_pair(new_block, block_size + 2)); 00591 capacity_ += block_size; 00592 // We don't touch the first and the last one. 00593 // We mark them free in reverse order, so that the insertion order 00594 // will correspond to the iterator order... 00595 for (size_type i = block_size; i >= 1; --i) 00596 put_on_free_list(new_block + i); 00597 // We insert this new block at the end. 00598 if (last_item == NULL) // First time 00599 { 00600 first_item = new_block; 00601 last_item = new_block + block_size + 1; 00602 set_type(first_item, NULL, START_END); 00603 } 00604 else 00605 { 00606 set_type(last_item, new_block, BLOCK_BOUNDARY); 00607 set_type(new_block, last_item, BLOCK_BOUNDARY); 00608 last_item = new_block + block_size + 1; 00609 } 00610 set_type(last_item, NULL, START_END); 00611 // Increase the block_size for the next time. 00612 block_size += 16; 00613 } 00614 00615 template < class T, class Allocator > 00616 inline 00617 bool operator==(const Compact_container<T, Allocator> &lhs, 00618 const Compact_container<T, Allocator> &rhs) 00619 { 00620 return lhs.size() == rhs.size() && 00621 std::equal(lhs.begin(), lhs.end(), rhs.begin()); 00622 } 00623 00624 template < class T, class Allocator > 00625 inline 00626 bool operator!=(const Compact_container<T, Allocator> &lhs, 00627 const Compact_container<T, Allocator> &rhs) 00628 { 00629 return ! (lhs == rhs); 00630 } 00631 00632 template < class T, class Allocator > 00633 inline 00634 bool operator< (const Compact_container<T, Allocator> &lhs, 00635 const Compact_container<T, Allocator> &rhs) 00636 { 00637 return std::lexicographical_compare(lhs.begin(), lhs.end(), 00638 rhs.begin(), rhs.end()); 00639 } 00640 00641 template < class T, class Allocator > 00642 inline 00643 bool operator> (const Compact_container<T, Allocator> &lhs, 00644 const Compact_container<T, Allocator> &rhs) 00645 { 00646 return rhs < lhs; 00647 } 00648 00649 template < class T, class Allocator > 00650 inline 00651 bool operator<=(const Compact_container<T, Allocator> &lhs, 00652 const Compact_container<T, Allocator> &rhs) 00653 { 00654 return ! (lhs > rhs); 00655 } 00656 00657 template < class T, class Allocator > 00658 inline 00659 bool operator>=(const Compact_container<T, Allocator> &lhs, 00660 const Compact_container<T, Allocator> &rhs) 00661 { 00662 return ! (lhs < rhs); 00663 } 00664 00665 namespace CGALi { 00666 00667 template < class DSC, bool Const > 00668 class CC_iterator 00669 { 00670 typedef typename DSC::iterator iterator; 00671 typedef CC_iterator<DSC, Const> Self; 00672 public: 00673 typedef typename DSC::value_type value_type; 00674 typedef typename DSC::size_type size_type; 00675 typedef typename DSC::difference_type difference_type; 00676 typedef typename boost::mpl::if_c< Const, const value_type*, 00677 value_type*>::type pointer; 00678 typedef typename boost::mpl::if_c< Const, const value_type&, 00679 value_type&>::type reference; 00680 typedef std::bidirectional_iterator_tag iterator_category; 00681 00682 // the initialization with NULL is required by our Handle concept. 00683 CC_iterator() 00684 { 00685 m_ptr.p = NULL; 00686 } 00687 00688 // Either a harmless copy-ctor, 00689 // or a conversion from iterator to const_iterator. 00690 CC_iterator (const iterator &it) 00691 { 00692 m_ptr.p = &(*it); 00693 } 00694 00695 // Same for assignment operator (otherwise MipsPro warns) 00696 CC_iterator & operator= (const iterator &it) 00697 { 00698 m_ptr.p = &(*it); 00699 return *this; 00700 } 00701 00702 // Construction from NULL 00703 CC_iterator (Nullptr_t CGAL_assertion_code(n)) 00704 { 00705 CGAL_assertion (n == NULL); 00706 m_ptr.p = NULL; 00707 } 00708 00709 private: 00710 00711 union { 00712 pointer p; 00713 void *vp; 00714 } m_ptr; 00715 00716 // Only Compact_container should access these constructors. 00717 friend class Compact_container<value_type, typename DSC::Al>; 00718 00719 // For begin() 00720 CC_iterator(pointer ptr, int, int) 00721 { 00722 m_ptr.p = ptr; 00723 if (m_ptr.p == NULL) // empty container. 00724 return; 00725 00726 ++(m_ptr.p); // if not empty, p = start 00727 if (DSC::type(m_ptr.p) == DSC::FREE) 00728 increment(); 00729 } 00730 00731 // Construction from raw pointer and for end(). 00732 CC_iterator(pointer ptr, int) 00733 { 00734 m_ptr.p = ptr; 00735 } 00736 00737 // NB : in case empty container, begin == end == NULL. 00738 void increment() 00739 { 00740 // It's either pointing to end(), or valid. 00741 CGAL_assertion_msg(m_ptr.p != NULL, 00742 "Doing ++ on empty container iterator ?"); 00743 CGAL_assertion_msg(DSC::type(m_ptr.p) != DSC::START_END, 00744 "Doing ++ on end() ?"); 00745 00746 // If it's not end(), then it's valid, we can do ++. 00747 do { 00748 ++(m_ptr.p); 00749 if (DSC::type(m_ptr.p) == DSC::USED || 00750 DSC::type(m_ptr.p) == DSC::START_END) 00751 return; 00752 00753 if (DSC::type(m_ptr.p) == DSC::BLOCK_BOUNDARY) 00754 m_ptr.p = DSC::clean_pointee(m_ptr.p); 00755 } while (true); 00756 } 00757 00758 void decrement() 00759 { 00760 // It's either pointing to end(), or valid. 00761 CGAL_assertion_msg(m_ptr.p != NULL, 00762 "Doing -- on empty container iterator ?"); 00763 CGAL_assertion_msg(DSC::type(m_ptr.p - 1) != DSC::START_END, 00764 "Doing -- on begin() ?"); 00765 00766 // If it's not begin(), then it's valid, we can do --. 00767 do { 00768 --m_ptr.p; 00769 if (DSC::type(m_ptr.p) == DSC::USED || 00770 DSC::type(m_ptr.p) == DSC::START_END) 00771 return; 00772 00773 if (DSC::type(m_ptr.p) == DSC::BLOCK_BOUNDARY) 00774 m_ptr.p = DSC::clean_pointee(m_ptr.p); 00775 } while (true); 00776 } 00777 00778 public: 00779 00780 Self & operator++() { increment(); return *this; } 00781 Self & operator--() { decrement(); return *this; } 00782 00783 Self operator++(int) { Self tmp(*this); ++(*this); return tmp; } 00784 Self operator--(int) { Self tmp(*this); --(*this); return tmp; } 00785 00786 reference operator*() const { return *(m_ptr.p); } 00787 00788 pointer operator->() const { return (m_ptr.p); } 00789 00790 // For std::less... 00791 bool operator<(const CC_iterator& other) const 00792 { 00793 return (m_ptr.p < other.m_ptr.p); 00794 } 00795 00796 // Can itself be used for bit-squatting. 00797 void * for_compact_container() const { return (m_ptr.vp); } 00798 void * & for_compact_container() { return (m_ptr.vp); } 00799 }; 00800 00801 template < class DSC, bool Const1, bool Const2 > 00802 inline 00803 bool operator==(const CC_iterator<DSC, Const1> &rhs, 00804 const CC_iterator<DSC, Const2> &lhs) 00805 { 00806 return &*rhs == &*lhs; 00807 } 00808 00809 template < class DSC, bool Const1, bool Const2 > 00810 inline 00811 bool operator!=(const CC_iterator<DSC, Const1> &rhs, 00812 const CC_iterator<DSC, Const2> &lhs) 00813 { 00814 return &*rhs != &*lhs; 00815 } 00816 00817 // Comparisons with NULL are part of CGAL's Handle concept... 00818 template < class DSC, bool Const > 00819 inline 00820 bool operator==(const CC_iterator<DSC, Const> &rhs, 00821 Nullptr_t CGAL_assertion_code(n)) 00822 { 00823 CGAL_assertion( n == NULL); 00824 return &*rhs == NULL; 00825 } 00826 00827 template < class DSC, bool Const > 00828 inline 00829 bool operator!=(const CC_iterator<DSC, Const> &rhs, 00830 Nullptr_t CGAL_assertion_code(n)) 00831 { 00832 CGAL_assertion( n == NULL); 00833 return &*rhs != NULL; 00834 } 00835 00836 } // namespace CGALi 00837 00838 CGAL_END_NAMESPACE 00839 00840 #endif // CGAL_COMPACT_CONTAINER_H