1
#ifndef INCLUDES_MYSQL_SQL_LIST_H
2
#define INCLUDES_MYSQL_SQL_LIST_H
3
/* Copyright (C) 2000-2003 MySQL AB
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.
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.
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
16
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
19
#ifdef USE_PRAGMA_INTERFACE
20
#pragma interface /* gcc class implementation */
23
/* mysql standard class memory allocator */
28
static void *operator new(size_t size) throw ()
30
return sql_alloc(size);
32
static void *operator new[](size_t size)
34
return sql_alloc(size);
36
static void *operator new[](size_t size, MEM_ROOT *mem_root) throw ()
37
{ return alloc_root(mem_root, size); }
38
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
39
{ return alloc_root(mem_root, size); }
40
static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); }
41
static void operator delete(void *ptr, MEM_ROOT *mem_root)
42
{ /* never called */ }
43
static void operator delete[](void *ptr, MEM_ROOT *mem_root)
44
{ /* never called */ }
45
static void operator delete[](void *ptr, size_t size) { TRASH(ptr, size); }
48
inline Sql_alloc() :dummy(0) {}
49
inline ~Sql_alloc() {}
52
inline ~Sql_alloc() {}
59
Basic single linked list
60
Used for item and item_buffs.
61
All list ends with a pointer to the 'end_of_list' element, which
62
data pointer is a null pointer and the next pointer points to itself.
63
This makes it very fast to traverse lists as we don't have to
64
test for a specialend condition for list that can't contain a null
70
list_node - a node of a single-linked list.
71
@note We never call a destructor for instances of this class.
74
struct list_node :public Sql_alloc
78
list_node(void *info_par,list_node *next_par)
79
:next(next_par),info(info_par)
81
list_node() /* For end_of_list */
89
extern list_node end_of_list;
91
class base_list :public Sql_alloc
94
list_node *first,**last;
99
inline void empty() { elements=0; first= &end_of_list; last=&first;}
100
inline base_list() { empty(); }
102
This is a shallow copy constructor that implicitly passes the ownership
103
from the source list to the new instance. The old instance is not
104
updated, so both objects end up sharing the same nodes. If one of
105
the instances then adds or removes a node, the other becomes out of
106
sync ('last' pointer), while still operational. Some old code uses and
107
relies on this behaviour. This logic is quite tricky: please do not use
110
inline base_list(const base_list &tmp) :Sql_alloc()
112
elements= tmp.elements;
114
last= elements ? tmp.last : &first;
117
Construct a deep copy of the argument in memory root mem_root.
118
The elements themselves are copied by pointer. If you also
119
need to copy elements by value, you should employ
120
list_copy_and_replace_each_value after creating a copy.
122
base_list(const base_list &rhs, MEM_ROOT *mem_root);
123
inline base_list(bool error) { }
124
inline bool push_back(void *info)
126
if (((*last)=new list_node(info, &end_of_list)))
128
last= &(*last)->next;
134
inline bool push_back(void *info, MEM_ROOT *mem_root)
136
if (((*last)=new (mem_root) list_node(info, &end_of_list)))
138
last= &(*last)->next;
144
inline bool push_front(void *info)
146
list_node *node=new list_node(info,first);
157
void remove(list_node **prev)
159
list_node *node=(*prev)->next;
162
else if (last == &(*prev)->next)
167
inline void concat(base_list *list)
169
if (!list->is_empty())
173
elements+= list->elements;
176
inline void *pop(void)
178
if (first == &end_of_list) return 0;
179
list_node *tmp=first;
185
inline void disjoin(base_list *list)
187
list_node **prev= &first;
188
list_node *node= first;
189
list_node *list_first= list->first;
191
while (node && node != list_first)
200
inline void prepand(base_list *list)
202
if (!list->is_empty())
206
elements+= list->elements;
212
inline void swap(base_list &rhs)
214
swap_variables(list_node *, first, rhs.first);
215
swap_variables(list_node **, last, rhs.last);
216
swap_variables(uint, elements, rhs.elements);
218
inline list_node* last_node() { return *last; }
219
inline list_node* first_node() { return first;}
220
inline void *head() { return first->info; }
221
inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
222
inline bool is_empty() { return first == &end_of_list ; }
223
inline list_node *last_ref() { return &end_of_list; }
224
friend class base_list_iterator;
225
friend class error_list;
226
friend class error_list_iterator;
228
#ifdef LIST_EXTRA_DEBUG
230
Check list invariants and print results into trace. Invariants are:
231
- (*last) points to end_of_list
232
- There are no NULLs in the list.
233
- base_list::elements is the number of elements in the list.
237
name Name to print to trace file
241
0 List invariants are not met.
244
bool check_list(const char *name)
246
base_list *list= this;
247
list_node *node= first;
250
while (node->next != &end_of_list)
254
DBUG_PRINT("list_invariants",("%s: error: NULL element in the list",
261
if (last != &(node->next))
263
DBUG_PRINT("list_invariants", ("%s: error: wrong last pointer", name));
266
if (cnt+1 != elements)
268
DBUG_PRINT("list_invariants", ("%s: error: wrong element count", name));
271
DBUG_PRINT("list_invariants", ("%s: list is ok", name));
274
#endif // LIST_EXTRA_DEBUG
277
void after(void *info,list_node *node)
279
list_node *new_node=new list_node(info,node->next);
282
if (last == &(node->next))
283
last= &new_node->next;
288
class base_list_iterator
292
list_node **el,**prev,*current;
293
void sublist(base_list &ls, uint elm)
301
:list(0), el(0), prev(0), current(0)
304
base_list_iterator(base_list &list_par)
307
inline void init(base_list &list_par)
315
inline void *next(void)
320
return current->info;
322
inline void *next_fast(void)
329
inline void rewind(void)
333
inline void *replace(void *element)
334
{ // Return old element
335
void *tmp=current->info;
336
DBUG_ASSERT(current->info != 0);
337
current->info=element;
340
void *replace(base_list &new_list)
342
void *ret_value=current->info;
343
if (!new_list.is_empty())
345
*new_list.last=current->next;
346
current->info=new_list.first->info;
347
current->next=new_list.first->next;
348
if ((list->last == ¤t->next) && (new_list.elements > 1))
349
list->last= new_list.last;
350
list->elements+=new_list.elements-1;
352
return ret_value; // return old element
354
inline void remove(void) // Remove current
358
current=0; // Safeguard
360
void after(void *element) // Insert element after current
362
list->after(element,current);
363
current=current->next;
366
inline void **ref(void) // Get reference pointer
368
return ¤t->info;
370
inline bool is_last(void)
372
return el == &list->last_ref()->next;
374
friend class error_list_iterator;
377
template <class T> class List :public base_list
380
inline List() :base_list() {}
381
inline List(const List<T> &tmp) :base_list(tmp) {}
382
inline List(const List<T> &tmp, MEM_ROOT *mem_root) :
383
base_list(tmp, mem_root) {}
384
inline bool push_back(T *a) { return base_list::push_back(a); }
385
inline bool push_back(T *a, MEM_ROOT *mem_root)
386
{ return base_list::push_back(a, mem_root); }
387
inline bool push_front(T *a) { return base_list::push_front(a); }
388
inline T* head() {return (T*) base_list::head(); }
389
inline T** head_ref() {return (T**) base_list::head_ref(); }
390
inline T* pop() {return (T*) base_list::pop(); }
391
inline void concat(List<T> *list) { base_list::concat(list); }
392
inline void disjoin(List<T> *list) { base_list::disjoin(list); }
393
inline void prepand(List<T> *list) { base_list::prepand(list); }
394
void delete_elements(void)
396
list_node *element,*next;
397
for (element=first; element != &end_of_list; element=next)
400
delete (T*) element->info;
407
template <class T> class List_iterator :public base_list_iterator
410
List_iterator(List<T> &a) : base_list_iterator(a) {}
411
List_iterator() : base_list_iterator() {}
412
inline void init(List<T> &a) { base_list_iterator::init(a); }
413
inline T* operator++(int) { return (T*) base_list_iterator::next(); }
414
inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); }
415
inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
416
inline void rewind(void) { base_list_iterator::rewind(); }
417
inline void remove() { base_list_iterator::remove(); }
418
inline void after(T *a) { base_list_iterator::after(a); }
419
inline T** ref(void) { return (T**) base_list_iterator::ref(); }
423
template <class T> class List_iterator_fast :public base_list_iterator
426
inline T *replace(T *a) { return (T*) 0; }
427
inline T *replace(List<T> &a) { return (T*) 0; }
428
inline void remove(void) { }
429
inline void after(T *a) { }
430
inline T** ref(void) { return (T**) 0; }
433
inline List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
434
inline List_iterator_fast() : base_list_iterator() {}
435
inline void init(List<T> &a) { base_list_iterator::init(a); }
436
inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
437
inline void rewind(void) { base_list_iterator::rewind(); }
438
void sublist(List<T> &list_arg, uint el_arg)
440
base_list_iterator::sublist(list_arg, el_arg);
446
A simple intrusive list which automaticly removes element from list
447
on delete (for THD element)
452
struct ilink **prev,*next;
453
static void *operator new(size_t size)
455
return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE | ME_FATALERROR));
457
static void operator delete(void* ptr_arg, size_t size)
459
my_free((uchar*)ptr_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
468
/* Extra tests because element doesn't have to be linked */
469
if (prev) *prev= next;
470
if (next) next->prev=prev;
473
virtual ~ilink() { unlink(); } /*lint -e1740 */
477
/* Needed to be able to have an I_List of char* strings in mysqld.cc. */
479
class i_string: public ilink
483
i_string():ptr(0) { }
484
i_string(const char* s) : ptr(s) {}
487
/* needed for linked list of two strings for replicate-rewrite-db */
488
class i_string_pair: public ilink
493
i_string_pair():key(0),val(0) { }
494
i_string_pair(const char* key_arg, const char* val_arg) :
495
key(key_arg),val(val_arg) {}
499
template <class T> class I_List_iterator;
502
WARNING: copy constructor of this class does not create a usable
503
copy, as its members may point at each other.
509
struct ilink *first,last;
510
inline void empty() { first= &last; last.prev= &first; }
511
base_ilist() { empty(); }
512
inline bool is_empty() { return first == &last; }
513
inline void append(ilink *a)
515
first->prev= &a->next;
516
a->next=first; a->prev= &first; first=a;
518
inline void push_back(ilink *a)
525
inline struct ilink *get()
527
struct ilink *first_link=first;
528
if (first_link == &last)
530
first_link->unlink(); // Unlink from list
533
inline struct ilink *head()
535
return (first != &last) ? first : 0;
537
friend class base_list_iterator;
541
class base_ilist_iterator
544
struct ilink **el,*current;
546
base_ilist_iterator(base_ilist &list_par) :list(&list_par),
547
el(&list_par.first),current(0) {}
550
/* This is coded to allow push_back() while iterating */
552
if (current == &list->last) return 0;
560
class I_List :private base_ilist
563
I_List() :base_ilist() {}
564
inline void empty() { base_ilist::empty(); }
565
inline bool is_empty() { return base_ilist::is_empty(); }
566
inline void append(T* a) { base_ilist::append(a); }
567
inline void push_back(T* a) { base_ilist::push_back(a); }
568
inline T* get() { return (T*) base_ilist::get(); }
569
inline T* head() { return (T*) base_ilist::head(); }
571
friend class I_List_iterator<T>;
576
template <class T> class I_List_iterator :public base_ilist_iterator
579
I_List_iterator(I_List<T> &a) : base_ilist_iterator(a) {}
580
inline T* operator++(int) { return (T*) base_ilist_iterator::next(); }
584
Make a deep copy of each list element.
586
@note A template function and not a template method of class List
587
is employed because of explicit template instantiation:
588
in server code there are explicit instantiations of List<T> and
589
an explicit instantiation of a template requires that any method
590
of the instantiated class used in the template can be resolved.
591
Evidently not all template arguments have clone() method with
594
@return You must query the error state in THD for out-of-memory
595
situation after calling this function.
598
template <typename T>
601
list_copy_and_replace_each_value(List<T> &list, MEM_ROOT *mem_root)
603
/* Make a deep copy of each element */
604
List_iterator<T> it(list);
607
it.replace(el->clone(mem_root));
610
#endif // INCLUDES_MYSQL_SQL_LIST_H