My Project
sql_list.h
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= &current->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 == &current->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= &current->next;
00457   }
00458   inline void **ref(void)                       // Get reference pointer
00459   {
00460     return &current->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= &current->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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines