~drizzle-trunk/drizzle/development

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