My Project
|
00001 #ifndef INCLUDES_MYSQL_SQL_LIST_H 00002 #define INCLUDES_MYSQL_SQL_LIST_H 00003 /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation; version 2 of the License. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software Foundation, 00016 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ 00017 00018 #include "sql_alloc.h" 00019 #include "my_global.h" 00020 #include "my_sys.h" 00021 #include "m_string.h" /* for TRASH */ 00022 00023 #include "my_sys.h" /* alloc_root, TRASH, MY_WME, 00024 MY_FAE, MY_ALLOW_ZERO_PTR */ 00025 #include "m_string.h" 00026 #include "thr_malloc.h" /* sql_alloc */ 00027 00028 00036 template <typename T> 00037 class SQL_I_List :public Sql_alloc 00038 { 00039 public: 00040 uint elements; 00042 T *first; 00044 T **next; 00045 00046 SQL_I_List() { empty(); } 00047 00048 SQL_I_List(const SQL_I_List &tmp) : Sql_alloc() 00049 { 00050 elements= tmp.elements; 00051 first= tmp.first; 00052 next= elements ? tmp.next : &first; 00053 } 00054 00055 inline void empty() 00056 { 00057 elements= 0; 00058 first= NULL; 00059 next= &first; 00060 } 00061 00062 inline void link_in_list(T *element, T **next_ptr) 00063 { 00064 elements++; 00065 (*next)= element; 00066 next= next_ptr; 00067 *next= NULL; 00068 } 00069 00070 inline void save_and_clear(SQL_I_List<T> *save) 00071 { 00072 *save= *this; 00073 empty(); 00074 } 00075 00076 inline void push_front(SQL_I_List<T> *save) 00077 { 00078 /* link current list last */ 00079 *save->next= first; 00080 first= save->first; 00081 elements+= save->elements; 00082 } 00083 00084 inline void push_back(SQL_I_List<T> *save) 00085 { 00086 if (save->first) 00087 { 00088 *next= save->first; 00089 next= save->next; 00090 elements+= save->elements; 00091 } 00092 } 00093 }; 00094 00095 00096 /* 00097 Basic single linked list 00098 Used for item and item_buffs. 00099 All list ends with a pointer to the 'end_of_list' element, which 00100 data pointer is a null pointer and the next pointer points to itself. 00101 This makes it very fast to traverse lists as we don't have to 00102 test for a specialend condition for list that can't contain a null 00103 pointer. 00104 */ 00105 00106 00112 struct list_node :public Sql_alloc 00113 { 00114 list_node *next; 00115 void *info; 00116 list_node(void *info_par,list_node *next_par) 00117 :next(next_par),info(info_par) 00118 {} 00119 list_node() /* For end_of_list */ 00120 { 00121 info= 0; 00122 next= this; 00123 } 00124 }; 00125 00126 00127 extern MYSQL_PLUGIN_IMPORT list_node end_of_list; 00128 00142 typedef int (*Node_cmp_func)(void *n1, void *n2, void *arg); 00143 00144 class base_list :public Sql_alloc 00145 { 00146 protected: 00147 list_node *first,**last; 00148 00149 public: 00150 uint elements; 00151 00152 bool operator==(const base_list &rhs) const 00153 { 00154 return 00155 elements == rhs.elements && 00156 first == rhs.first && 00157 last == rhs.last; 00158 } 00159 00160 inline void empty() { elements=0; first= &end_of_list; last=&first;} 00161 inline base_list() { empty(); } 00171 inline base_list(const base_list &tmp) :Sql_alloc() 00172 { 00173 elements= tmp.elements; 00174 first= tmp.first; 00175 last= elements ? tmp.last : &first; 00176 } 00183 base_list(const base_list &rhs, MEM_ROOT *mem_root); 00184 inline base_list(bool error) { } 00185 inline bool push_back(void *info) 00186 { 00187 if (((*last)=new list_node(info, &end_of_list))) 00188 { 00189 last= &(*last)->next; 00190 elements++; 00191 return 0; 00192 } 00193 return 1; 00194 } 00195 inline bool push_back(void *info, MEM_ROOT *mem_root) 00196 { 00197 if (((*last)=new (mem_root) list_node(info, &end_of_list))) 00198 { 00199 last= &(*last)->next; 00200 elements++; 00201 return 0; 00202 } 00203 return 1; 00204 } 00205 inline bool push_front(void *info) 00206 { 00207 list_node *node=new list_node(info,first); 00208 if (node) 00209 { 00210 if (last == &first) 00211 last= &node->next; 00212 first=node; 00213 elements++; 00214 return 0; 00215 } 00216 return 1; 00217 } 00218 void remove(list_node **prev) 00219 { 00220 list_node *node=(*prev)->next; 00221 if (!--elements) 00222 last= &first; 00223 else if (last == &(*prev)->next) 00224 last= prev; 00225 delete *prev; 00226 *prev=node; 00227 } 00228 inline void concat(base_list *list) 00229 { 00230 if (!list->is_empty()) 00231 { 00232 *last= list->first; 00233 last= list->last; 00234 elements+= list->elements; 00235 } 00236 } 00237 inline void *pop(void) 00238 { 00239 if (first == &end_of_list) return 0; 00240 list_node *tmp=first; 00241 first=first->next; 00242 if (!--elements) 00243 last= &first; 00244 return tmp->info; 00245 } 00246 inline void disjoin(base_list *list) 00247 { 00248 list_node **prev= &first; 00249 list_node *node= first; 00250 list_node *list_first= list->first; 00251 elements=0; 00252 while (node && node != list_first) 00253 { 00254 prev= &node->next; 00255 node= node->next; 00256 elements++; 00257 } 00258 *prev= *last; 00259 last= prev; 00260 } 00261 inline void prepand(base_list *list) 00262 { 00263 if (!list->is_empty()) 00264 { 00265 *list->last= first; 00266 first= list->first; 00267 elements+= list->elements; 00268 } 00269 } 00285 void sort(Node_cmp_func cmp, void *arg) 00286 { 00287 if (elements < 2) 00288 return; 00289 for (list_node *n1= first; n1 && n1 != &end_of_list; n1= n1->next) 00290 { 00291 for (list_node *n2= n1->next; n2 && n2 != &end_of_list; n2= n2->next) 00292 { 00293 if ((*cmp)(n1->info, n2->info, arg) > 0) 00294 { 00295 void *tmp= n1->info; 00296 n1->info= n2->info; 00297 n2->info= tmp; 00298 } 00299 } 00300 } 00301 } 00305 inline void swap(base_list &rhs) 00306 { 00307 swap_variables(list_node *, first, rhs.first); 00308 swap_variables(list_node **, last, rhs.last); 00309 swap_variables(uint, elements, rhs.elements); 00310 } 00311 inline list_node* last_node() { return *last; } 00312 inline list_node* first_node() { return first;} 00313 inline void *head() { return first->info; } 00314 inline void **head_ref() { return first != &end_of_list ? &first->info : 0; } 00315 inline bool is_empty() const { return first == &end_of_list ; } 00316 inline list_node *last_ref() { return &end_of_list; } 00317 friend class base_list_iterator; 00318 friend class error_list; 00319 friend class error_list_iterator; 00320 00321 #ifdef LIST_EXTRA_DEBUG 00322 /* 00323 Check list invariants and print results into trace. Invariants are: 00324 - (*last) points to end_of_list 00325 - There are no NULLs in the list. 00326 - base_list::elements is the number of elements in the list. 00327 00328 SYNOPSIS 00329 check_list() 00330 name Name to print to trace file 00331 00332 RETURN 00333 1 The list is Ok. 00334 0 List invariants are not met. 00335 */ 00336 00337 bool check_list(const char *name) 00338 { 00339 base_list *list= this; 00340 list_node *node= first; 00341 uint cnt= 0; 00342 00343 while (node->next != &end_of_list) 00344 { 00345 if (!node->info) 00346 { 00347 DBUG_PRINT("list_invariants",("%s: error: NULL element in the list", 00348 name)); 00349 return FALSE; 00350 } 00351 node= node->next; 00352 cnt++; 00353 } 00354 if (last != &(node->next)) 00355 { 00356 DBUG_PRINT("list_invariants", ("%s: error: wrong last pointer", name)); 00357 return FALSE; 00358 } 00359 if (cnt+1 != elements) 00360 { 00361 DBUG_PRINT("list_invariants", ("%s: error: wrong element count", name)); 00362 return FALSE; 00363 } 00364 DBUG_PRINT("list_invariants", ("%s: list is ok", name)); 00365 return TRUE; 00366 } 00367 #endif // LIST_EXTRA_DEBUG 00368 00369 protected: 00370 void after(void *info,list_node *node) 00371 { 00372 list_node *new_node=new list_node(info,node->next); 00373 node->next=new_node; 00374 elements++; 00375 if (last == &(node->next)) 00376 last= &new_node->next; 00377 } 00378 }; 00379 00380 class base_list_iterator 00381 { 00382 protected: 00383 base_list *list; 00384 list_node **el,**prev,*current; 00385 void sublist(base_list &ls, uint elm) 00386 { 00387 ls.first= *el; 00388 ls.last= list->last; 00389 ls.elements= elm; 00390 } 00391 public: 00392 base_list_iterator() 00393 :list(0), el(0), prev(0), current(0) 00394 {} 00395 00396 base_list_iterator(base_list &list_par) 00397 { init(list_par); } 00398 00399 inline void init(base_list &list_par) 00400 { 00401 list= &list_par; 00402 el= &list_par.first; 00403 prev= 0; 00404 current= 0; 00405 } 00406 00407 inline void *next(void) 00408 { 00409 prev=el; 00410 current= *el; 00411 el= ¤t->next; 00412 return current->info; 00413 } 00414 inline void *next_fast(void) 00415 { 00416 list_node *tmp; 00417 tmp= *el; 00418 el= &tmp->next; 00419 return tmp->info; 00420 } 00421 inline void rewind(void) 00422 { 00423 el= &list->first; 00424 } 00425 inline void *replace(void *element) 00426 { // Return old element 00427 void *tmp=current->info; 00428 DBUG_ASSERT(current->info != 0); 00429 current->info=element; 00430 return tmp; 00431 } 00432 void *replace(base_list &new_list) 00433 { 00434 void *ret_value=current->info; 00435 if (!new_list.is_empty()) 00436 { 00437 *new_list.last=current->next; 00438 current->info=new_list.first->info; 00439 current->next=new_list.first->next; 00440 if ((list->last == ¤t->next) && (new_list.elements > 1)) 00441 list->last= new_list.last; 00442 list->elements+=new_list.elements-1; 00443 } 00444 return ret_value; // return old element 00445 } 00446 inline void remove(void) // Remove current 00447 { 00448 list->remove(prev); 00449 el=prev; 00450 current=0; // Safeguard 00451 } 00452 void after(void *element) // Insert element after current 00453 { 00454 list->after(element,current); 00455 current=current->next; 00456 el= ¤t->next; 00457 } 00458 inline void **ref(void) // Get reference pointer 00459 { 00460 return ¤t->info; 00461 } 00462 inline bool is_last(void) 00463 { 00464 return el == &list->last_ref()->next; 00465 } 00466 friend class error_list_iterator; 00467 }; 00468 00469 template <class T> class List :public base_list 00470 { 00471 public: 00472 inline List() :base_list() {} 00473 inline List(const List<T> &tmp) :base_list(tmp) {} 00474 inline List(const List<T> &tmp, MEM_ROOT *mem_root) : 00475 base_list(tmp, mem_root) {} 00476 /* 00477 Typecasting to (void *) it's necessary if we want to declare List<T> with 00478 constant T parameter (like List<const char>), since the untyped storage 00479 is "void *", and assignment of const pointer to "void *" is a syntax error. 00480 */ 00481 inline bool push_back(T *a) { return base_list::push_back((void *) a); } 00482 inline bool push_back(T *a, MEM_ROOT *mem_root) 00483 { return base_list::push_back((void *) a, mem_root); } 00484 inline bool push_front(T *a) { return base_list::push_front((void *) a); } 00485 inline T* head() {return (T*) base_list::head(); } 00486 inline T** head_ref() {return (T**) base_list::head_ref(); } 00487 inline T* pop() {return (T*) base_list::pop(); } 00488 inline void concat(List<T> *list) { base_list::concat(list); } 00489 inline void disjoin(List<T> *list) { base_list::disjoin(list); } 00490 inline void prepand(List<T> *list) { base_list::prepand(list); } 00491 void delete_elements(void) 00492 { 00493 list_node *element,*next; 00494 for (element=first; element != &end_of_list; element=next) 00495 { 00496 next=element->next; 00497 delete (T*) element->info; 00498 } 00499 empty(); 00500 } 00501 00502 using base_list::sort; 00503 }; 00504 00505 00506 template <class T> class List_iterator :public base_list_iterator 00507 { 00508 public: 00509 List_iterator(List<T> &a) : base_list_iterator(a) {} 00510 List_iterator() : base_list_iterator() {} 00511 inline void init(List<T> &a) { base_list_iterator::init(a); } 00512 inline T* operator++(int) { return (T*) base_list_iterator::next(); } 00513 inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); } 00514 inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); } 00515 inline void rewind(void) { base_list_iterator::rewind(); } 00516 inline void remove() { base_list_iterator::remove(); } 00517 inline void after(T *a) { base_list_iterator::after(a); } 00518 inline T** ref(void) { return (T**) base_list_iterator::ref(); } 00519 }; 00520 00521 00522 template <class T> class List_iterator_fast :public base_list_iterator 00523 { 00524 protected: 00525 inline T *replace(T *a) { return (T*) 0; } 00526 inline T *replace(List<T> &a) { return (T*) 0; } 00527 inline void remove(void) { } 00528 inline void after(T *a) { } 00529 inline T** ref(void) { return (T**) 0; } 00530 00531 public: 00532 inline List_iterator_fast(List<T> &a) : base_list_iterator(a) {} 00533 inline List_iterator_fast() : base_list_iterator() {} 00534 inline void init(List<T> &a) { base_list_iterator::init(a); } 00535 inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); } 00536 inline void rewind(void) { base_list_iterator::rewind(); } 00537 void sublist(List<T> &list_arg, uint el_arg) 00538 { 00539 base_list_iterator::sublist(list_arg, el_arg); 00540 } 00541 }; 00542 00543 00544 template <typename T> class base_ilist; 00545 template <typename T> class base_ilist_iterator; 00546 00547 /* 00548 A simple intrusive list which automaticly removes element from list 00549 on delete (for THD element) 00550 NOTE: this inherently unsafe, since we rely on <T> to have 00551 the same layout as ilink<T> (see base_ilist::sentinel). 00552 Please consider using a different strategy for linking objects. 00553 */ 00554 00555 template <typename T> 00556 class ilink 00557 { 00558 T **prev, *next; 00559 public: 00560 ilink() : prev(NULL), next(NULL) {} 00561 00562 void unlink() 00563 { 00564 /* Extra tests because element doesn't have to be linked */ 00565 if (prev) *prev= next; 00566 if (next) next->prev=prev; 00567 prev= NULL; 00568 next= NULL; 00569 } 00570 00571 virtual ~ilink() { unlink(); } /*lint -e1740 */ 00572 00573 friend class base_ilist<T>; 00574 friend class base_ilist_iterator<T>; 00575 }; 00576 00577 00578 /* Needed to be able to have an I_List of char* strings in mysqld.cc. */ 00579 00580 class i_string: public ilink<i_string> 00581 { 00582 public: 00583 const char* ptr; 00584 i_string():ptr(0) { } 00585 i_string(const char* s) : ptr(s) {} 00586 }; 00587 00588 /* needed for linked list of two strings for replicate-rewrite-db */ 00589 class i_string_pair: public ilink<i_string_pair> 00590 { 00591 public: 00592 const char* key; 00593 const char* val; 00594 i_string_pair():key(0),val(0) { } 00595 i_string_pair(const char* key_arg, const char* val_arg) : 00596 key(key_arg),val(val_arg) {} 00597 }; 00598 00599 00600 template <class T> class I_List_iterator; 00601 00602 00603 template<typename T> 00604 class base_ilist 00605 { 00606 T *first; 00607 ilink<T> sentinel; 00608 public: 00609 void empty() { 00610 first= static_cast<T*>(&sentinel); 00611 sentinel.prev= &first; 00612 } 00613 base_ilist() { empty(); } 00614 bool is_empty() const { return first == static_cast<const T*>(&sentinel); } 00615 00617 void push_front(T *a) 00618 { 00619 first->prev= &a->next; 00620 a->next= first; 00621 a->prev= &first; 00622 first= a; 00623 } 00624 00626 void push_back(T *a) 00627 { 00628 *sentinel.prev= a; 00629 a->next= static_cast<T*>(&sentinel); 00630 a->prev= sentinel.prev; 00631 sentinel.prev= &a->next; 00632 } 00633 00634 // Unlink first element, and return it. 00635 T *get() 00636 { 00637 if (is_empty()) 00638 return NULL; 00639 T *first_link= first; 00640 first_link->unlink(); 00641 return first_link; 00642 } 00643 00644 T *head() { return is_empty() ? NULL : first; } 00645 00653 void move_elements_to(base_ilist *new_owner) 00654 { 00655 DBUG_ASSERT(new_owner->is_empty()); 00656 new_owner->first= first; 00657 new_owner->sentinel= sentinel; 00658 empty(); 00659 } 00660 00661 friend class base_ilist_iterator<T>; 00662 private: 00663 /* 00664 We don't want to allow copying of this class, as that would give us 00665 two list heads containing the same elements. 00666 So we declare, but don't define copy CTOR and assignment operator. 00667 */ 00668 base_ilist(const base_ilist&); 00669 void operator=(const base_ilist&); 00670 }; 00671 00672 00673 template<typename T> 00674 class base_ilist_iterator 00675 { 00676 base_ilist<T> *list; 00677 T **el, *current; 00678 public: 00679 base_ilist_iterator(base_ilist<T> &list_par) : 00680 list(&list_par), 00681 el(&list_par.first), 00682 current(NULL) 00683 {} 00684 00685 T *next(void) 00686 { 00687 /* This is coded to allow push_back() while iterating */ 00688 current= *el; 00689 if (current == static_cast<T*>(&list->sentinel)) 00690 return NULL; 00691 el= ¤t->next; 00692 return current; 00693 } 00694 }; 00695 00696 00697 template <class T> 00698 class I_List :private base_ilist<T> 00699 { 00700 public: 00701 using base_ilist<T>::empty; 00702 using base_ilist<T>::is_empty; 00703 using base_ilist<T>::get; 00704 using base_ilist<T>::push_front; 00705 using base_ilist<T>::push_back; 00706 using base_ilist<T>::head; 00707 void move_elements_to(I_List<T>* new_owner) { 00708 base_ilist<T>::move_elements_to(new_owner); 00709 } 00710 #ifndef _lint 00711 friend class I_List_iterator<T>; 00712 #endif 00713 }; 00714 00715 00716 template <class T> 00717 class I_List_iterator :public base_ilist_iterator<T> 00718 { 00719 public: 00720 I_List_iterator(I_List<T> &a) : base_ilist_iterator<T>(a) {} 00721 inline T* operator++(int) { return base_ilist_iterator<T>::next(); } 00722 }; 00723 00739 template <typename T> 00740 inline 00741 void 00742 list_copy_and_replace_each_value(List<T> &list, MEM_ROOT *mem_root) 00743 { 00744 /* Make a deep copy of each element */ 00745 List_iterator<T> it(list); 00746 T *el; 00747 while ((el= it++)) 00748 it.replace(el->clone(mem_root)); 00749 } 00750 00751 void free_list(I_List <i_string_pair> *list); 00752 void free_list(I_List <i_string> *list); 00753 00754 #endif // INCLUDES_MYSQL_SQL_LIST_H