MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sql_list.h
1 #ifndef INCLUDES_MYSQL_SQL_LIST_H
2 #define INCLUDES_MYSQL_SQL_LIST_H
3 /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software Foundation,
16  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
17 
18 #include "sql_alloc.h"
19 #include "my_global.h"
20 #include "my_sys.h"
21 #include "m_string.h" /* for TRASH */
22 
23 #include "my_sys.h" /* alloc_root, TRASH, MY_WME,
24  MY_FAE, MY_ALLOW_ZERO_PTR */
25 #include "m_string.h"
26 #include "thr_malloc.h" /* sql_alloc */
27 
28 
36 template <typename T>
37 class SQL_I_List :public Sql_alloc
38 {
39 public:
40  uint elements;
42  T *first;
44  T **next;
45 
46  SQL_I_List() { empty(); }
47 
48  SQL_I_List(const SQL_I_List &tmp) : Sql_alloc()
49  {
50  elements= tmp.elements;
51  first= tmp.first;
52  next= elements ? tmp.next : &first;
53  }
54 
55  inline void empty()
56  {
57  elements= 0;
58  first= NULL;
59  next= &first;
60  }
61 
62  inline void link_in_list(T *element, T **next_ptr)
63  {
64  elements++;
65  (*next)= element;
66  next= next_ptr;
67  *next= NULL;
68  }
69 
70  inline void save_and_clear(SQL_I_List<T> *save)
71  {
72  *save= *this;
73  empty();
74  }
75 
76  inline void push_front(SQL_I_List<T> *save)
77  {
78  /* link current list last */
79  *save->next= first;
80  first= save->first;
81  elements+= save->elements;
82  }
83 
84  inline void push_back(SQL_I_List<T> *save)
85  {
86  if (save->first)
87  {
88  *next= save->first;
89  next= save->next;
90  elements+= save->elements;
91  }
92  }
93 };
94 
95 
96 /*
97  Basic single linked list
98  Used for item and item_buffs.
99  All list ends with a pointer to the 'end_of_list' element, which
100  data pointer is a null pointer and the next pointer points to itself.
101  This makes it very fast to traverse lists as we don't have to
102  test for a specialend condition for list that can't contain a null
103  pointer.
104 */
105 
106 
112 struct list_node :public Sql_alloc
113 {
114  list_node *next;
115  void *info;
116  list_node(void *info_par,list_node *next_par)
117  :next(next_par),info(info_par)
118  {}
119  list_node() /* For end_of_list */
120  {
121  info= 0;
122  next= this;
123  }
124 };
125 
126 
127 extern MYSQL_PLUGIN_IMPORT list_node end_of_list;
128 
142 typedef int (*Node_cmp_func)(void *n1, void *n2, void *arg);
143 
144 class base_list :public Sql_alloc
145 {
146 protected:
147  list_node *first,**last;
148 
149 public:
150  uint elements;
151 
152  bool operator==(const base_list &rhs) const
153  {
154  return
155  elements == rhs.elements &&
156  first == rhs.first &&
157  last == rhs.last;
158  }
159 
160  inline void empty() { elements=0; first= &end_of_list; last=&first;}
161  inline base_list() { empty(); }
171  inline base_list(const base_list &tmp) :Sql_alloc()
172  {
173  elements= tmp.elements;
174  first= tmp.first;
175  last= elements ? tmp.last : &first;
176  }
183  base_list(const base_list &rhs, MEM_ROOT *mem_root);
184  inline base_list(bool error) { }
185  inline bool push_back(void *info)
186  {
187  if (((*last)=new list_node(info, &end_of_list)))
188  {
189  last= &(*last)->next;
190  elements++;
191  return 0;
192  }
193  return 1;
194  }
195  inline bool push_back(void *info, MEM_ROOT *mem_root)
196  {
197  if (((*last)=new (mem_root) list_node(info, &end_of_list)))
198  {
199  last= &(*last)->next;
200  elements++;
201  return 0;
202  }
203  return 1;
204  }
205  inline bool push_front(void *info)
206  {
207  list_node *node=new list_node(info,first);
208  if (node)
209  {
210  if (last == &first)
211  last= &node->next;
212  first=node;
213  elements++;
214  return 0;
215  }
216  return 1;
217  }
218  void remove(list_node **prev)
219  {
220  list_node *node=(*prev)->next;
221  if (!--elements)
222  last= &first;
223  else if (last == &(*prev)->next)
224  last= prev;
225  delete *prev;
226  *prev=node;
227  }
228  inline void concat(base_list *list)
229  {
230  if (!list->is_empty())
231  {
232  *last= list->first;
233  last= list->last;
234  elements+= list->elements;
235  }
236  }
237  inline void *pop(void)
238  {
239  if (first == &end_of_list) return 0;
240  list_node *tmp=first;
241  first=first->next;
242  if (!--elements)
243  last= &first;
244  return tmp->info;
245  }
246  inline void disjoin(base_list *list)
247  {
248  list_node **prev= &first;
249  list_node *node= first;
250  list_node *list_first= list->first;
251  elements=0;
252  while (node && node != list_first)
253  {
254  prev= &node->next;
255  node= node->next;
256  elements++;
257  }
258  *prev= *last;
259  last= prev;
260  }
261  inline void prepand(base_list *list)
262  {
263  if (!list->is_empty())
264  {
265  *list->last= first;
266  first= list->first;
267  elements+= list->elements;
268  }
269  }
285  void sort(Node_cmp_func cmp, void *arg)
286  {
287  if (elements < 2)
288  return;
289  for (list_node *n1= first; n1 && n1 != &end_of_list; n1= n1->next)
290  {
291  for (list_node *n2= n1->next; n2 && n2 != &end_of_list; n2= n2->next)
292  {
293  if ((*cmp)(n1->info, n2->info, arg) > 0)
294  {
295  void *tmp= n1->info;
296  n1->info= n2->info;
297  n2->info= tmp;
298  }
299  }
300  }
301  }
305  inline void swap(base_list &rhs)
306  {
307  swap_variables(list_node *, first, rhs.first);
308  swap_variables(list_node **, last, rhs.last);
309  swap_variables(uint, elements, rhs.elements);
310  }
311  inline list_node* last_node() { return *last; }
312  inline list_node* first_node() { return first;}
313  inline void *head() { return first->info; }
314  inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
315  inline bool is_empty() const { return first == &end_of_list ; }
316  inline list_node *last_ref() { return &end_of_list; }
317  friend class base_list_iterator;
318  friend class error_list;
319  friend class error_list_iterator;
320 
321 #ifdef LIST_EXTRA_DEBUG
322  /*
323  Check list invariants and print results into trace. Invariants are:
324  - (*last) points to end_of_list
325  - There are no NULLs in the list.
326  - base_list::elements is the number of elements in the list.
327 
328  SYNOPSIS
329  check_list()
330  name Name to print to trace file
331 
332  RETURN
333  1 The list is Ok.
334  0 List invariants are not met.
335  */
336 
337  bool check_list(const char *name)
338  {
339  base_list *list= this;
340  list_node *node= first;
341  uint cnt= 0;
342 
343  while (node->next != &end_of_list)
344  {
345  if (!node->info)
346  {
347  DBUG_PRINT("list_invariants",("%s: error: NULL element in the list",
348  name));
349  return FALSE;
350  }
351  node= node->next;
352  cnt++;
353  }
354  if (last != &(node->next))
355  {
356  DBUG_PRINT("list_invariants", ("%s: error: wrong last pointer", name));
357  return FALSE;
358  }
359  if (cnt+1 != elements)
360  {
361  DBUG_PRINT("list_invariants", ("%s: error: wrong element count", name));
362  return FALSE;
363  }
364  DBUG_PRINT("list_invariants", ("%s: list is ok", name));
365  return TRUE;
366  }
367 #endif // LIST_EXTRA_DEBUG
368 
369 protected:
370  void after(void *info,list_node *node)
371  {
372  list_node *new_node=new list_node(info,node->next);
373  node->next=new_node;
374  elements++;
375  if (last == &(node->next))
376  last= &new_node->next;
377  }
378 };
379 
381 {
382 protected:
383  base_list *list;
384  list_node **el,**prev,*current;
385  void sublist(base_list &ls, uint elm)
386  {
387  ls.first= *el;
388  ls.last= list->last;
389  ls.elements= elm;
390  }
391 public:
393  :list(0), el(0), prev(0), current(0)
394  {}
395 
396  base_list_iterator(base_list &list_par)
397  { init(list_par); }
398 
399  inline void init(base_list &list_par)
400  {
401  list= &list_par;
402  el= &list_par.first;
403  prev= 0;
404  current= 0;
405  }
406 
407  inline void *next(void)
408  {
409  prev=el;
410  current= *el;
411  el= &current->next;
412  return current->info;
413  }
414  inline void *next_fast(void)
415  {
416  list_node *tmp;
417  tmp= *el;
418  el= &tmp->next;
419  return tmp->info;
420  }
421  inline void rewind(void)
422  {
423  el= &list->first;
424  }
425  inline void *replace(void *element)
426  { // Return old element
427  void *tmp=current->info;
428  DBUG_ASSERT(current->info != 0);
429  current->info=element;
430  return tmp;
431  }
432  void *replace(base_list &new_list)
433  {
434  void *ret_value=current->info;
435  if (!new_list.is_empty())
436  {
437  *new_list.last=current->next;
438  current->info=new_list.first->info;
439  current->next=new_list.first->next;
440  if ((list->last == &current->next) && (new_list.elements > 1))
441  list->last= new_list.last;
442  list->elements+=new_list.elements-1;
443  }
444  return ret_value; // return old element
445  }
446  inline void remove(void) // Remove current
447  {
448  list->remove(prev);
449  el=prev;
450  current=0; // Safeguard
451  }
452  void after(void *element) // Insert element after current
453  {
454  list->after(element,current);
455  current=current->next;
456  el= &current->next;
457  }
458  inline void **ref(void) // Get reference pointer
459  {
460  return &current->info;
461  }
462  inline bool is_last(void)
463  {
464  return el == &list->last_ref()->next;
465  }
466  friend class error_list_iterator;
467 };
468 
469 template <class T> class List :public base_list
470 {
471 public:
472  inline List() :base_list() {}
473  inline List(const List<T> &tmp) :base_list(tmp) {}
474  inline List(const List<T> &tmp, MEM_ROOT *mem_root) :
475  base_list(tmp, mem_root) {}
476  /*
477  Typecasting to (void *) it's necessary if we want to declare List<T> with
478  constant T parameter (like List<const char>), since the untyped storage
479  is "void *", and assignment of const pointer to "void *" is a syntax error.
480  */
481  inline bool push_back(T *a) { return base_list::push_back((void *) a); }
482  inline bool push_back(T *a, MEM_ROOT *mem_root)
483  { return base_list::push_back((void *) a, mem_root); }
484  inline bool push_front(T *a) { return base_list::push_front((void *) a); }
485  inline T* head() {return (T*) base_list::head(); }
486  inline T** head_ref() {return (T**) base_list::head_ref(); }
487  inline T* pop() {return (T*) base_list::pop(); }
488  inline void concat(List<T> *list) { base_list::concat(list); }
489  inline void disjoin(List<T> *list) { base_list::disjoin(list); }
490  inline void prepand(List<T> *list) { base_list::prepand(list); }
491  void delete_elements(void)
492  {
493  list_node *element,*next;
494  for (element=first; element != &end_of_list; element=next)
495  {
496  next=element->next;
497  delete (T*) element->info;
498  }
499  empty();
500  }
501 
502  using base_list::sort;
503 };
504 
505 
506 template <class T> class List_iterator :public base_list_iterator
507 {
508 public:
511  inline void init(List<T> &a) { base_list_iterator::init(a); }
512  inline T* operator++(int) { return (T*) base_list_iterator::next(); }
513  inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); }
514  inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
515  inline void rewind(void) { base_list_iterator::rewind(); }
516  inline void remove() { base_list_iterator::remove(); }
517  inline void after(T *a) { base_list_iterator::after(a); }
518  inline T** ref(void) { return (T**) base_list_iterator::ref(); }
519 };
520 
521 
522 template <class T> class List_iterator_fast :public base_list_iterator
523 {
524 protected:
525  inline T *replace(T *a) { return (T*) 0; }
526  inline T *replace(List<T> &a) { return (T*) 0; }
527  inline void remove(void) { }
528  inline void after(T *a) { }
529  inline T** ref(void) { return (T**) 0; }
530 
531 public:
533  inline List_iterator_fast() : base_list_iterator() {}
534  inline void init(List<T> &a) { base_list_iterator::init(a); }
535  inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
536  inline void rewind(void) { base_list_iterator::rewind(); }
537  void sublist(List<T> &list_arg, uint el_arg)
538  {
539  base_list_iterator::sublist(list_arg, el_arg);
540  }
541 };
542 
543 
544 template <typename T> class base_ilist;
545 template <typename T> class base_ilist_iterator;
546 
547 /*
548  A simple intrusive list which automaticly removes element from list
549  on delete (for THD element)
550  NOTE: this inherently unsafe, since we rely on <T> to have
551  the same layout as ilink<T> (see base_ilist::sentinel).
552  Please consider using a different strategy for linking objects.
553 */
554 
555 template <typename T>
556 class ilink
557 {
558  T **prev, *next;
559 public:
560  ilink() : prev(NULL), next(NULL) {}
561 
562  void unlink()
563  {
564  /* Extra tests because element doesn't have to be linked */
565  if (prev) *prev= next;
566  if (next) next->prev=prev;
567  prev= NULL;
568  next= NULL;
569  }
570 
571  virtual ~ilink() { unlink(); } /*lint -e1740 */
572 
573  friend class base_ilist<T>;
574  friend class base_ilist_iterator<T>;
575 };
576 
577 
578 /* Needed to be able to have an I_List of char* strings in mysqld.cc. */
579 
580 class i_string: public ilink<i_string>
581 {
582 public:
583  const char* ptr;
584  i_string():ptr(0) { }
585  i_string(const char* s) : ptr(s) {}
586 };
587 
588 /* needed for linked list of two strings for replicate-rewrite-db */
589 class i_string_pair: public ilink<i_string_pair>
590 {
591 public:
592  const char* key;
593  const char* val;
594  i_string_pair():key(0),val(0) { }
595  i_string_pair(const char* key_arg, const char* val_arg) :
596  key(key_arg),val(val_arg) {}
597 };
598 
599 
600 template <class T> class I_List_iterator;
601 
602 
603 template<typename T>
605 {
606  T *first;
607  ilink<T> sentinel;
608 public:
609  void empty() {
610  first= static_cast<T*>(&sentinel);
611  sentinel.prev= &first;
612  }
613  base_ilist() { empty(); }
614  bool is_empty() const { return first == static_cast<const T*>(&sentinel); }
615 
617  void push_front(T *a)
618  {
619  first->prev= &a->next;
620  a->next= first;
621  a->prev= &first;
622  first= a;
623  }
624 
626  void push_back(T *a)
627  {
628  *sentinel.prev= a;
629  a->next= static_cast<T*>(&sentinel);
630  a->prev= sentinel.prev;
631  sentinel.prev= &a->next;
632  }
633 
634  // Unlink first element, and return it.
635  T *get()
636  {
637  if (is_empty())
638  return NULL;
639  T *first_link= first;
640  first_link->unlink();
641  return first_link;
642  }
643 
644  T *head() { return is_empty() ? NULL : first; }
645 
653  void move_elements_to(base_ilist *new_owner)
654  {
655  DBUG_ASSERT(new_owner->is_empty());
656  new_owner->first= first;
657  new_owner->sentinel= sentinel;
658  empty();
659  }
660 
661  friend class base_ilist_iterator<T>;
662  private:
663  /*
664  We don't want to allow copying of this class, as that would give us
665  two list heads containing the same elements.
666  So we declare, but don't define copy CTOR and assignment operator.
667  */
668  base_ilist(const base_ilist&);
669  void operator=(const base_ilist&);
670 };
671 
672 
673 template<typename T>
675 {
676  base_ilist<T> *list;
677  T **el, *current;
678 public:
680  list(&list_par),
681  el(&list_par.first),
682  current(NULL)
683  {}
684 
685  T *next(void)
686  {
687  /* This is coded to allow push_back() while iterating */
688  current= *el;
689  if (current == static_cast<T*>(&list->sentinel))
690  return NULL;
691  el= &current->next;
692  return current;
693  }
694 };
695 
696 
697 template <class T>
698 class I_List :private base_ilist<T>
699 {
700 public:
701  using base_ilist<T>::empty;
703  using base_ilist<T>::get;
706  using base_ilist<T>::head;
707  void move_elements_to(I_List<T>* new_owner) {
709  }
710 #ifndef _lint
711  friend class I_List_iterator<T>;
712 #endif
713 };
714 
715 
716 template <class T>
718 {
719 public:
721  inline T* operator++(int) { return base_ilist_iterator<T>::next(); }
722 };
723 
739 template <typename T>
740 inline
741 void
742 list_copy_and_replace_each_value(List<T> &list, MEM_ROOT *mem_root)
743 {
744  /* Make a deep copy of each element */
745  List_iterator<T> it(list);
746  T *el;
747  while ((el= it++))
748  it.replace(el->clone(mem_root));
749 }
750 
751 void free_list(I_List <i_string_pair> *list);
752 void free_list(I_List <i_string> *list);
753 
754 #endif // INCLUDES_MYSQL_SQL_LIST_H