~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
#ifndef INCLUDES_MYSQL_SQL_LIST_H
2
#define INCLUDES_MYSQL_SQL_LIST_H
3
/* Copyright (C) 2000-2003 MySQL AB
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
16
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
17
18
19
#ifdef USE_PRAGMA_INTERFACE
20
#pragma interface			/* gcc class implementation */
21
#endif
243.1.1 by Jay Pipes
* Pulled Object_creation_ctx and Default_creation_ctx out of mysql_priv.h
22
                                  
23
/** Struct to handle simple linked lists. */
24
typedef struct st_sql_list {
25
  uint elements;
26
  uchar *first;
27
  uchar **next;
28
29
  st_sql_list() {}                              /* Remove gcc warning */
30
  inline void empty()
31
  {
32
    elements=0;
33
    first=0;
34
    next= &first;
35
  }
36
  inline void link_in_list(uchar *element,uchar **next_ptr)
37
  {
38
    elements++;
39
    (*next)=element;
40
    next= next_ptr;
41
    *next=0;
42
  }
43
  inline void save_and_clear(struct st_sql_list *save)
44
  {
45
    *save= *this;
46
    empty();
47
  }
48
  inline void push_front(struct st_sql_list *save)
49
  {
50
    *save->next= first;				/* link current list last */
51
    first= save->first;
52
    elements+= save->elements;
53
  }
54
  inline void push_back(struct st_sql_list *save)
55
  {
56
    if (save->first)
57
    {
58
      *next= save->first;
59
      next= save->next;
60
      elements+= save->elements;
61
    }
62
  }
63
} SQL_LIST;
1 by brian
clean slate
64
65
/* mysql standard class memory allocator */
66
class Sql_alloc
67
{
68
public:
69
  static void *operator new(size_t size) throw ()
70
  {
71
    return sql_alloc(size);
72
  }
73
  static void *operator new[](size_t size)
74
  {
75
    return sql_alloc(size);
76
  }
77
  static void *operator new[](size_t size, MEM_ROOT *mem_root) throw ()
78
  { return alloc_root(mem_root, size); }
79
  static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
80
  { return alloc_root(mem_root, size); }
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
81
  static void operator delete(void *ptr __attribute__((unused)),
82
                              size_t size __attribute__((unused)))
53.2.32 by Monty Taylor
First large swath at getting handler stuff clean.
83
  { TRASH(ptr, size); }
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
84
  static void operator delete(void *ptr __attribute__((unused)),
85
                              MEM_ROOT *mem_root __attribute__((unused)))
86
  { /* never called */ }
87
  static void operator delete[](void *ptr __attribute__((unused)),
88
                                MEM_ROOT *mem_root __attribute__((unused)))
89
  { /* never called */ }
90
  static void operator delete[](void *ptr __attribute__((unused)),
91
                                size_t size __attribute__((unused)))
53.2.32 by Monty Taylor
First large swath at getting handler stuff clean.
92
  { TRASH(ptr, size); }
1 by brian
clean slate
93
#ifdef HAVE_purify
94
  bool dummy;
95
  inline Sql_alloc() :dummy(0) {}
96
  inline ~Sql_alloc() {}
97
#else
98
  inline Sql_alloc() {}
99
  inline ~Sql_alloc() {}
100
#endif
101
102
};
103
104
105
/*
106
  Basic single linked list
107
  Used for item and item_buffs.
108
  All list ends with a pointer to the 'end_of_list' element, which
109
  data pointer is a null pointer and the next pointer points to itself.
110
  This makes it very fast to traverse lists as we don't have to
111
  test for a specialend condition for list that can't contain a null
112
  pointer.
113
*/
114
115
116
/**
117
  list_node - a node of a single-linked list.
118
  @note We never call a destructor for instances of this class.
119
*/
120
121
struct list_node :public Sql_alloc
122
{
123
  list_node *next;
124
  void *info;
125
  list_node(void *info_par,list_node *next_par)
126
    :next(next_par),info(info_par)
127
  {}
128
  list_node()					/* For end_of_list */
129
  {
130
    info= 0;
131
    next= this;
132
  }
133
};
134
135
136
extern list_node end_of_list;
137
138
class base_list :public Sql_alloc
139
{
140
protected:
141
  list_node *first,**last;
142
143
public:
144
  uint elements;
145
146
  inline void empty() { elements=0; first= &end_of_list; last=&first;}
147
  inline base_list() { empty(); }
148
  /**
149
    This is a shallow copy constructor that implicitly passes the ownership
150
    from the source list to the new instance. The old instance is not
151
    updated, so both objects end up sharing the same nodes. If one of
152
    the instances then adds or removes a node, the other becomes out of
153
    sync ('last' pointer), while still operational. Some old code uses and
154
    relies on this behaviour. This logic is quite tricky: please do not use
155
    it in any new code.
156
  */
157
  inline base_list(const base_list &tmp) :Sql_alloc()
158
  {
159
    elements= tmp.elements;
160
    first= tmp.first;
161
    last= elements ? tmp.last : &first;
162
  }
163
  /**
164
    Construct a deep copy of the argument in memory root mem_root.
165
    The elements themselves are copied by pointer. If you also
166
    need to copy elements by value, you should employ
167
    list_copy_and_replace_each_value after creating a copy.
168
  */
169
  base_list(const base_list &rhs, MEM_ROOT *mem_root);
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
170
  inline base_list(bool error __attribute__((unused))) { }
1 by brian
clean slate
171
  inline bool push_back(void *info)
172
  {
173
    if (((*last)=new list_node(info, &end_of_list)))
174
    {
175
      last= &(*last)->next;
176
      elements++;
177
      return 0;
178
    }
179
    return 1;
180
  }
181
  inline bool push_back(void *info, MEM_ROOT *mem_root)
182
  {
183
    if (((*last)=new (mem_root) list_node(info, &end_of_list)))
184
    {
185
      last= &(*last)->next;
186
      elements++;
187
      return 0;
188
    }
189
    return 1;
190
  }
191
  inline bool push_front(void *info)
192
  {
193
    list_node *node=new list_node(info,first);
194
    if (node)
195
    {
196
      if (last == &first)
197
	last= &node->next;
198
      first=node;
199
      elements++;
200
      return 0;
201
    }
202
    return 1;
203
  }
204
  void remove(list_node **prev)
205
  {
206
    list_node *node=(*prev)->next;
207
    if (!--elements)
208
      last= &first;
209
    else if (last == &(*prev)->next)
210
      last= prev;
211
    delete *prev;
212
    *prev=node;
213
  }
214
  inline void concat(base_list *list)
215
  {
216
    if (!list->is_empty())
217
    {
218
      *last= list->first;
219
      last= list->last;
220
      elements+= list->elements;
221
    }
222
  }
223
  inline void *pop(void)
224
  {
225
    if (first == &end_of_list) return 0;
226
    list_node *tmp=first;
227
    first=first->next;
228
    if (!--elements)
229
      last= &first;
230
    return tmp->info;
231
  }
232
  inline void disjoin(base_list *list)
233
  {
234
    list_node **prev= &first;
235
    list_node *node= first;
236
    list_node *list_first= list->first;
237
    elements=0;
238
    while (node && node != list_first)
239
    {
240
      prev= &node->next;
241
      node= node->next;
242
      elements++;
243
    }
244
    *prev= *last;
245
    last= prev;
246
  }
247
  inline void prepand(base_list *list)
248
  {
249
    if (!list->is_empty())
250
    {
251
      *list->last= first;
252
      first= list->first;
253
      elements+= list->elements;
254
    }
255
  }
256
  /**
257
    Swap two lists.
258
  */
259
  inline void swap(base_list &rhs)
260
  {
261
    swap_variables(list_node *, first, rhs.first);
262
    swap_variables(list_node **, last, rhs.last);
263
    swap_variables(uint, elements, rhs.elements);
264
  }
265
  inline list_node* last_node() { return *last; }
266
  inline list_node* first_node() { return first;}
267
  inline void *head() { return first->info; }
268
  inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
269
  inline bool is_empty() { return first == &end_of_list ; }
270
  inline list_node *last_ref() { return &end_of_list; }
271
  friend class base_list_iterator;
272
  friend class error_list;
273
  friend class error_list_iterator;
274
275
#ifdef LIST_EXTRA_DEBUG
276
  /*
277
    Check list invariants and print results into trace. Invariants are:
278
      - (*last) points to end_of_list
279
      - There are no NULLs in the list.
280
      - base_list::elements is the number of elements in the list.
281
282
    SYNOPSIS
283
      check_list()
284
        name  Name to print to trace file
285
286
    RETURN 
287
      1  The list is Ok.
288
      0  List invariants are not met.
289
  */
290
291
  bool check_list(const char *name)
292
  {
293
    base_list *list= this;
294
    list_node *node= first;
295
    uint cnt= 0;
296
297
    while (node->next != &end_of_list)
298
    {
299
      if (!node->info)
300
      {
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
301
        return false;
1 by brian
clean slate
302
      }
303
      node= node->next;
304
      cnt++;
305
    }
306
    if (last != &(node->next))
307
    {
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
308
      return false;
1 by brian
clean slate
309
    }
310
    if (cnt+1 != elements)
311
    {
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
312
      return false;
1 by brian
clean slate
313
    }
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
314
    return true;
1 by brian
clean slate
315
  }
316
#endif // LIST_EXTRA_DEBUG
317
318
protected:
319
  void after(void *info,list_node *node)
320
  {
321
    list_node *new_node=new list_node(info,node->next);
322
    node->next=new_node;
323
    elements++;
324
    if (last == &(node->next))
325
      last= &new_node->next;
326
  }
327
};
328
329
330
class base_list_iterator
331
{
332
protected:
333
  base_list *list;
334
  list_node **el,**prev,*current;
335
  void sublist(base_list &ls, uint elm)
336
  {
337
    ls.first= *el;
338
    ls.last= list->last;
339
    ls.elements= elm;
340
  }
341
public:
342
  base_list_iterator() 
343
    :list(0), el(0), prev(0), current(0)
344
  {}
345
346
  base_list_iterator(base_list &list_par) 
347
  { init(list_par); }
348
349
  inline void init(base_list &list_par)
350
  {
351
    list= &list_par;
352
    el= &list_par.first;
353
    prev= 0;
354
    current= 0;
355
  }
356
357
  inline void *next(void)
358
  {
359
    prev=el;
360
    current= *el;
361
    el= &current->next;
362
    return current->info;
363
  }
364
  inline void *next_fast(void)
365
  {
366
    list_node *tmp;
367
    tmp= *el;
368
    el= &tmp->next;
369
    return tmp->info;
370
  }
371
  inline void rewind(void)
372
  {
373
    el= &list->first;
374
  }
375
  inline void *replace(void *element)
376
  {						// Return old element
377
    void *tmp=current->info;
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
378
    assert(current->info != 0);
1 by brian
clean slate
379
    current->info=element;
380
    return tmp;
381
  }
382
  void *replace(base_list &new_list)
383
  {
384
    void *ret_value=current->info;
385
    if (!new_list.is_empty())
386
    {
387
      *new_list.last=current->next;
388
      current->info=new_list.first->info;
389
      current->next=new_list.first->next;
390
      if ((list->last == &current->next) && (new_list.elements > 1))
391
	list->last= new_list.last;
392
      list->elements+=new_list.elements-1;
393
    }
394
    return ret_value;				// return old element
395
  }
396
  inline void remove(void)			// Remove current
397
  {
398
    list->remove(prev);
399
    el=prev;
400
    current=0;					// Safeguard
401
  }
402
  void after(void *element)			// Insert element after current
403
  {
404
    list->after(element,current);
405
    current=current->next;
406
    el= &current->next;
407
  }
408
  inline void **ref(void)			// Get reference pointer
409
  {
410
    return &current->info;
411
  }
412
  inline bool is_last(void)
413
  {
414
    return el == &list->last_ref()->next;
415
  }
416
  friend class error_list_iterator;
417
};
418
419
template <class T> class List :public base_list
420
{
421
public:
422
  inline List() :base_list() {}
423
  inline List(const List<T> &tmp) :base_list(tmp) {}
424
  inline List(const List<T> &tmp, MEM_ROOT *mem_root) :
425
    base_list(tmp, mem_root) {}
426
  inline bool push_back(T *a) { return base_list::push_back(a); }
427
  inline bool push_back(T *a, MEM_ROOT *mem_root)
428
  { return base_list::push_back(a, mem_root); }
429
  inline bool push_front(T *a) { return base_list::push_front(a); }
430
  inline T* head() {return (T*) base_list::head(); }
431
  inline T** head_ref() {return (T**) base_list::head_ref(); }
432
  inline T* pop()  {return (T*) base_list::pop(); }
433
  inline void concat(List<T> *list) { base_list::concat(list); }
434
  inline void disjoin(List<T> *list) { base_list::disjoin(list); }
435
  inline void prepand(List<T> *list) { base_list::prepand(list); }
436
  void delete_elements(void)
437
  {
438
    list_node *element,*next;
439
    for (element=first; element != &end_of_list; element=next)
440
    {
441
      next=element->next;
442
      delete (T*) element->info;
443
    }
444
    empty();
445
  }
446
};
447
448
449
template <class T> class List_iterator :public base_list_iterator
450
{
451
public:
452
  List_iterator(List<T> &a) : base_list_iterator(a) {}
453
  List_iterator() : base_list_iterator() {}
454
  inline void init(List<T> &a) { base_list_iterator::init(a); }
455
  inline T* operator++(int) { return (T*) base_list_iterator::next(); }
456
  inline T *replace(T *a)   { return (T*) base_list_iterator::replace(a); }
457
  inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
458
  inline void rewind(void)  { base_list_iterator::rewind(); }
459
  inline void remove()      { base_list_iterator::remove(); }
460
  inline void after(T *a)   { base_list_iterator::after(a); }
461
  inline T** ref(void)	    { return (T**) base_list_iterator::ref(); }
462
};
463
464
465
template <class T> class List_iterator_fast :public base_list_iterator
466
{
467
protected:
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
468
  inline T *replace(T *a __attribute__((unused)))   { return (T*) 0; }
469
  inline T *replace(List<T> &a __attribute__((unused))) { return (T*) 0; }
1 by brian
clean slate
470
  inline void remove(void)  { }
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
471
  inline void after(T *a __attribute__((unused)))   { }
1 by brian
clean slate
472
  inline T** ref(void)	    { return (T**) 0; }
473
474
public:
475
  inline List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
476
  inline List_iterator_fast() : base_list_iterator() {}
477
  inline void init(List<T> &a) { base_list_iterator::init(a); }
478
  inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
479
  inline void rewind(void)  { base_list_iterator::rewind(); }
480
  void sublist(List<T> &list_arg, uint el_arg)
481
  {
482
    base_list_iterator::sublist(list_arg, el_arg);
483
  }
484
};
485
486
487
/*
488
  A simple intrusive list which automaticly removes element from list
489
  on delete (for THD element)
490
*/
491
492
struct ilink
493
{
494
  struct ilink **prev,*next;
495
  static void *operator new(size_t size)
496
  {
497
    return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE | ME_FATALERROR));
498
  }
53.2.32 by Monty Taylor
First large swath at getting handler stuff clean.
499
  static void operator delete(void* ptr_arg,
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
500
                              size_t size __attribute__((unused)))
1 by brian
clean slate
501
  {
502
     my_free((uchar*)ptr_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
503
  }
504
505
  inline ilink()
506
  {
507
    prev=0; next=0;
508
  }
509
  inline void unlink()
510
  {
511
    /* Extra tests because element doesn't have to be linked */
512
    if (prev) *prev= next;
513
    if (next) next->prev=prev;
514
    prev=0 ; next=0;
515
  }
516
  virtual ~ilink() { unlink(); }		/*lint -e1740 */
517
};
518
519
520
/* Needed to be able to have an I_List of char* strings in mysqld.cc. */
521
522
class i_string: public ilink
523
{
524
public:
525
  const char* ptr;
526
  i_string():ptr(0) { }
527
  i_string(const char* s) : ptr(s) {}
528
};
529
530
/* needed for linked list of two strings for replicate-rewrite-db */
531
class i_string_pair: public ilink
532
{
533
public:
534
  const char* key;
535
  const char* val;
536
  i_string_pair():key(0),val(0) { }
537
  i_string_pair(const char* key_arg, const char* val_arg) : 
538
    key(key_arg),val(val_arg) {}
539
};
540
541
542
template <class T> class I_List_iterator;
543
544
/*
545
  WARNING: copy constructor of this class does not create a usable
546
  copy, as its members may point at each other.
547
*/
548
549
class base_ilist
550
{
551
public:
552
  struct ilink *first,last;
553
  inline void empty() { first= &last; last.prev= &first; }
554
  base_ilist() { empty(); }
555
  inline bool is_empty() {  return first == &last; }
556
  inline void append(ilink *a)
557
  {
558
    first->prev= &a->next;
559
    a->next=first; a->prev= &first; first=a;
560
  }
561
  inline void push_back(ilink *a)
562
  {
563
    *last.prev= a;
564
    a->next= &last;
565
    a->prev= last.prev;
566
    last.prev= &a->next;
567
  }
568
  inline struct ilink *get()
569
  {
570
    struct ilink *first_link=first;
571
    if (first_link == &last)
572
      return 0;
573
    first_link->unlink();			// Unlink from list
574
    return first_link;
575
  }
576
  inline struct ilink *head()
577
  {
578
    return (first != &last) ? first : 0;
579
  }
580
  friend class base_list_iterator;
581
};
582
583
584
class base_ilist_iterator
585
{
586
  base_ilist *list;
587
  struct ilink **el,*current;
588
public:
589
  base_ilist_iterator(base_ilist &list_par) :list(&list_par),
590
    el(&list_par.first),current(0) {}
591
  void *next(void)
592
  {
593
    /* This is coded to allow push_back() while iterating */
594
    current= *el;
595
    if (current == &list->last) return 0;
596
    el= &current->next;
597
    return current;
598
  }
599
};
600
601
602
template <class T>
603
class I_List :private base_ilist
604
{
605
public:
606
  I_List() :base_ilist()	{}
607
  inline void empty()		{ base_ilist::empty(); }
608
  inline bool is_empty()        { return base_ilist::is_empty(); } 
609
  inline void append(T* a)	{ base_ilist::append(a); }
610
  inline void push_back(T* a)	{ base_ilist::push_back(a); }
611
  inline T* get()		{ return (T*) base_ilist::get(); }
612
  inline T* head()		{ return (T*) base_ilist::head(); }
613
#ifndef _lint
614
  friend class I_List_iterator<T>;
615
#endif
616
};
617
618
619
template <class T> class I_List_iterator :public base_ilist_iterator
620
{
621
public:
622
  I_List_iterator(I_List<T> &a) : base_ilist_iterator(a) {}
623
  inline T* operator++(int) { return (T*) base_ilist_iterator::next(); }
624
};
625
626
/**
627
  Make a deep copy of each list element.
628
629
  @note A template function and not a template method of class List
630
  is employed because of explicit template instantiation:
631
  in server code there are explicit instantiations of List<T> and
632
  an explicit instantiation of a template requires that any method
633
  of the instantiated class used in the template can be resolved.
634
  Evidently not all template arguments have clone() method with
635
  the right signature.
636
637
  @return You must query the error state in THD for out-of-memory
638
  situation after calling this function.
639
*/
640
641
template <typename T>
642
inline
643
void
644
list_copy_and_replace_each_value(List<T> &list, MEM_ROOT *mem_root)
645
{
646
  /* Make a deep copy of each element */
647
  List_iterator<T> it(list);
648
  T *el;
649
  while ((el= it++))
650
    it.replace(el->clone(mem_root));
651
}
652
653
#endif // INCLUDES_MYSQL_SQL_LIST_H