~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>
677.1.5 by Monty Taylor
Fixed a couple of build issues.
26
#include <stdlib.h>
520.6.6 by Monty Taylor
Removed sql_alloc.h from common_includes.
27
#include <drizzled/sql_alloc.h>
322.2.2 by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter.
28
243.1.1 by Jay Pipes
* Pulled Object_creation_ctx and Default_creation_ctx out of mysql_priv.h
29
/** Struct to handle simple linked lists. */
30
typedef struct st_sql_list {
482 by Brian Aker
Remove uint.
31
  uint32_t elements;
481 by Brian Aker
Remove all of uchar.
32
  unsigned char *first;
33
  unsigned char **next;
243.1.1 by Jay Pipes
* Pulled Object_creation_ctx and Default_creation_ctx out of mysql_priv.h
34
35
  st_sql_list() {}                              /* Remove gcc warning */
36
  inline void empty()
37
  {
38
    elements=0;
39
    first=0;
40
    next= &first;
41
  }
481 by Brian Aker
Remove all of uchar.
42
  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
43
  {
44
    elements++;
45
    (*next)=element;
46
    next= next_ptr;
47
    *next=0;
48
  }
49
  inline void save_and_clear(struct st_sql_list *save)
50
  {
51
    *save= *this;
52
    empty();
53
  }
54
  inline void push_front(struct st_sql_list *save)
55
  {
56
    *save->next= first;				/* link current list last */
57
    first= save->first;
58
    elements+= save->elements;
59
  }
60
  inline void push_back(struct st_sql_list *save)
61
  {
62
    if (save->first)
63
    {
64
      *next= save->first;
65
      next= save->next;
66
      elements+= save->elements;
67
    }
68
  }
69
} SQL_LIST;
1 by brian
clean slate
70
71
/*
72
  Basic single linked list
73
  Used for item and item_buffs.
74
  All list ends with a pointer to the 'end_of_list' element, which
75
  data pointer is a null pointer and the next pointer points to itself.
76
  This makes it very fast to traverse lists as we don't have to
77
  test for a specialend condition for list that can't contain a null
78
  pointer.
79
*/
80
81
82
/**
83
  list_node - a node of a single-linked list.
84
  @note We never call a destructor for instances of this class.
85
*/
86
87
struct list_node :public Sql_alloc
88
{
89
  list_node *next;
90
  void *info;
91
  list_node(void *info_par,list_node *next_par)
92
    :next(next_par),info(info_par)
93
  {}
94
  list_node()					/* For end_of_list */
95
  {
96
    info= 0;
97
    next= this;
98
  }
99
};
100
101
102
extern list_node end_of_list;
103
104
class base_list :public Sql_alloc
105
{
106
protected:
107
  list_node *first,**last;
108
109
public:
482 by Brian Aker
Remove uint.
110
  uint32_t elements;
1 by brian
clean slate
111
112
  inline void empty() { elements=0; first= &end_of_list; last=&first;}
113
  inline base_list() { empty(); }
114
  /**
115
    This is a shallow copy constructor that implicitly passes the ownership
116
    from the source list to the new instance. The old instance is not
117
    updated, so both objects end up sharing the same nodes. If one of
118
    the instances then adds or removes a node, the other becomes out of
119
    sync ('last' pointer), while still operational. Some old code uses and
120
    relies on this behaviour. This logic is quite tricky: please do not use
121
    it in any new code.
122
  */
123
  inline base_list(const base_list &tmp) :Sql_alloc()
124
  {
125
    elements= tmp.elements;
126
    first= tmp.first;
127
    last= elements ? tmp.last : &first;
128
  }
129
  /**
130
    Construct a deep copy of the argument in memory root mem_root.
131
    The elements themselves are copied by pointer. If you also
132
    need to copy elements by value, you should employ
133
    list_copy_and_replace_each_value after creating a copy.
134
  */
135
  base_list(const base_list &rhs, MEM_ROOT *mem_root);
644 by Brian Aker
Clean up warnings for Solaris.
136
  inline base_list(bool) { }
1 by brian
clean slate
137
  inline bool push_back(void *info)
138
  {
139
    if (((*last)=new list_node(info, &end_of_list)))
140
    {
141
      last= &(*last)->next;
142
      elements++;
143
      return 0;
144
    }
145
    return 1;
146
  }
147
  inline bool push_back(void *info, MEM_ROOT *mem_root)
148
  {
149
    if (((*last)=new (mem_root) list_node(info, &end_of_list)))
150
    {
151
      last= &(*last)->next;
152
      elements++;
153
      return 0;
154
    }
155
    return 1;
156
  }
157
  inline bool push_front(void *info)
158
  {
159
    list_node *node=new list_node(info,first);
160
    if (node)
161
    {
162
      if (last == &first)
163
	last= &node->next;
164
      first=node;
165
      elements++;
166
      return 0;
167
    }
168
    return 1;
169
  }
170
  void remove(list_node **prev)
171
  {
172
    list_node *node=(*prev)->next;
173
    if (!--elements)
174
      last= &first;
175
    else if (last == &(*prev)->next)
176
      last= prev;
177
    delete *prev;
178
    *prev=node;
179
  }
180
  inline void concat(base_list *list)
181
  {
182
    if (!list->is_empty())
183
    {
184
      *last= list->first;
185
      last= list->last;
186
      elements+= list->elements;
187
    }
188
  }
189
  inline void *pop(void)
190
  {
191
    if (first == &end_of_list) return 0;
192
    list_node *tmp=first;
193
    first=first->next;
194
    if (!--elements)
195
      last= &first;
196
    return tmp->info;
197
  }
198
  inline void disjoin(base_list *list)
199
  {
200
    list_node **prev= &first;
201
    list_node *node= first;
202
    list_node *list_first= list->first;
203
    elements=0;
204
    while (node && node != list_first)
205
    {
206
      prev= &node->next;
207
      node= node->next;
208
      elements++;
209
    }
210
    *prev= *last;
211
    last= prev;
212
  }
213
  inline void prepand(base_list *list)
214
  {
215
    if (!list->is_empty())
216
    {
217
      *list->last= first;
218
      first= list->first;
219
      elements+= list->elements;
220
    }
221
  }
222
  /**
223
    Swap two lists.
224
  */
225
  inline void swap(base_list &rhs)
226
  {
322.2.2 by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter.
227
    std::swap(first, rhs.first);
228
    std::swap(last, rhs.last);
229
    std::swap(elements, rhs.elements);
1 by brian
clean slate
230
  }
231
  inline list_node* last_node() { return *last; }
232
  inline list_node* first_node() { return first;}
233
  inline void *head() { return first->info; }
234
  inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
235
  inline bool is_empty() { return first == &end_of_list ; }
236
  inline list_node *last_ref() { return &end_of_list; }
237
  friend class base_list_iterator;
238
  friend class error_list;
239
  friend class error_list_iterator;
240
241
#ifdef LIST_EXTRA_DEBUG
242
  /*
243
    Check list invariants and print results into trace. Invariants are:
244
      - (*last) points to end_of_list
245
      - There are no NULLs in the list.
246
      - base_list::elements is the number of elements in the list.
247
248
    SYNOPSIS
249
      check_list()
250
        name  Name to print to trace file
251
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
252
    RETURN
1 by brian
clean slate
253
      1  The list is Ok.
254
      0  List invariants are not met.
255
  */
256
257
  bool check_list(const char *name)
258
  {
259
    base_list *list= this;
260
    list_node *node= first;
482 by Brian Aker
Remove uint.
261
    uint32_t cnt= 0;
1 by brian
clean slate
262
263
    while (node->next != &end_of_list)
264
    {
265
      if (!node->info)
266
      {
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
267
        return false;
1 by brian
clean slate
268
      }
269
      node= node->next;
270
      cnt++;
271
    }
272
    if (last != &(node->next))
273
    {
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
274
      return false;
1 by brian
clean slate
275
    }
276
    if (cnt+1 != elements)
277
    {
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
278
      return false;
1 by brian
clean slate
279
    }
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
280
    return true;
1 by brian
clean slate
281
  }
282
#endif // LIST_EXTRA_DEBUG
283
284
protected:
285
  void after(void *info,list_node *node)
286
  {
287
    list_node *new_node=new list_node(info,node->next);
288
    node->next=new_node;
289
    elements++;
290
    if (last == &(node->next))
291
      last= &new_node->next;
292
  }
293
};
294
295
296
class base_list_iterator
297
{
298
protected:
299
  base_list *list;
300
  list_node **el,**prev,*current;
482 by Brian Aker
Remove uint.
301
  void sublist(base_list &ls, uint32_t elm)
1 by brian
clean slate
302
  {
303
    ls.first= *el;
304
    ls.last= list->last;
305
    ls.elements= elm;
306
  }
307
public:
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
308
  base_list_iterator()
1 by brian
clean slate
309
    :list(0), el(0), prev(0), current(0)
310
  {}
311
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
312
  base_list_iterator(base_list &list_par)
1 by brian
clean slate
313
  { init(list_par); }
314
315
  inline void init(base_list &list_par)
316
  {
317
    list= &list_par;
318
    el= &list_par.first;
319
    prev= 0;
320
    current= 0;
321
  }
322
323
  inline void *next(void)
324
  {
325
    prev=el;
326
    current= *el;
327
    el= &current->next;
328
    return current->info;
329
  }
330
  inline void *next_fast(void)
331
  {
332
    list_node *tmp;
333
    tmp= *el;
334
    el= &tmp->next;
335
    return tmp->info;
336
  }
337
  inline void rewind(void)
338
  {
339
    el= &list->first;
340
  }
341
  inline void *replace(void *element)
342
  {						// Return old element
343
    void *tmp=current->info;
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
344
    assert(current->info != 0);
1 by brian
clean slate
345
    current->info=element;
346
    return tmp;
347
  }
348
  void *replace(base_list &new_list)
349
  {
350
    void *ret_value=current->info;
351
    if (!new_list.is_empty())
352
    {
353
      *new_list.last=current->next;
354
      current->info=new_list.first->info;
355
      current->next=new_list.first->next;
356
      if ((list->last == &current->next) && (new_list.elements > 1))
357
	list->last= new_list.last;
358
      list->elements+=new_list.elements-1;
359
    }
360
    return ret_value;				// return old element
361
  }
362
  inline void remove(void)			// Remove current
363
  {
364
    list->remove(prev);
365
    el=prev;
366
    current=0;					// Safeguard
367
  }
368
  void after(void *element)			// Insert element after current
369
  {
370
    list->after(element,current);
371
    current=current->next;
372
    el= &current->next;
373
  }
374
  inline void **ref(void)			// Get reference pointer
375
  {
376
    return &current->info;
377
  }
378
  inline bool is_last(void)
379
  {
380
    return el == &list->last_ref()->next;
381
  }
382
  friend class error_list_iterator;
383
};
384
385
template <class T> class List :public base_list
386
{
387
public:
388
  inline List() :base_list() {}
389
  inline List(const List<T> &tmp) :base_list(tmp) {}
390
  inline List(const List<T> &tmp, MEM_ROOT *mem_root) :
391
    base_list(tmp, mem_root) {}
392
  inline bool push_back(T *a) { return base_list::push_back(a); }
393
  inline bool push_back(T *a, MEM_ROOT *mem_root)
394
  { return base_list::push_back(a, mem_root); }
395
  inline bool push_front(T *a) { return base_list::push_front(a); }
396
  inline T* head() {return (T*) base_list::head(); }
397
  inline T** head_ref() {return (T**) base_list::head_ref(); }
398
  inline T* pop()  {return (T*) base_list::pop(); }
399
  inline void concat(List<T> *list) { base_list::concat(list); }
400
  inline void disjoin(List<T> *list) { base_list::disjoin(list); }
401
  inline void prepand(List<T> *list) { base_list::prepand(list); }
402
  void delete_elements(void)
403
  {
404
    list_node *element,*next;
405
    for (element=first; element != &end_of_list; element=next)
406
    {
407
      next=element->next;
408
      delete (T*) element->info;
409
    }
410
    empty();
411
  }
412
};
413
414
415
template <class T> class List_iterator :public base_list_iterator
416
{
417
public:
418
  List_iterator(List<T> &a) : base_list_iterator(a) {}
419
  List_iterator() : base_list_iterator() {}
420
  inline void init(List<T> &a) { base_list_iterator::init(a); }
421
  inline T* operator++(int) { return (T*) base_list_iterator::next(); }
422
  inline T *replace(T *a)   { return (T*) base_list_iterator::replace(a); }
423
  inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
424
  inline void rewind(void)  { base_list_iterator::rewind(); }
425
  inline void remove()      { base_list_iterator::remove(); }
426
  inline void after(T *a)   { base_list_iterator::after(a); }
427
  inline T** ref(void)	    { return (T**) base_list_iterator::ref(); }
428
};
429
430
431
template <class T> class List_iterator_fast :public base_list_iterator
432
{
433
protected:
644 by Brian Aker
Clean up warnings for Solaris.
434
  inline T *replace(T *)   { return (T*) 0; }
435
  inline T *replace(List<T> &) { return (T*) 0; }
1 by brian
clean slate
436
  inline void remove(void)  { }
644 by Brian Aker
Clean up warnings for Solaris.
437
  inline void after(T *a)   { }
1 by brian
clean slate
438
  inline T** ref(void)	    { return (T**) 0; }
439
440
public:
441
  inline List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
442
  inline List_iterator_fast() : base_list_iterator() {}
443
  inline void init(List<T> &a) { base_list_iterator::init(a); }
444
  inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
445
  inline void rewind(void)  { base_list_iterator::rewind(); }
482 by Brian Aker
Remove uint.
446
  void sublist(List<T> &list_arg, uint32_t el_arg)
1 by brian
clean slate
447
  {
448
    base_list_iterator::sublist(list_arg, el_arg);
449
  }
450
};
451
452
453
/*
454
  A simple intrusive list which automaticly removes element from list
520.1.21 by Brian Aker
THD -> Session rename
455
  on delete (for Session element)
1 by brian
clean slate
456
*/
457
458
struct ilink
459
{
460
  struct ilink **prev,*next;
461
  static void *operator new(size_t size)
462
  {
895 by Brian Aker
Completion (?) of uint conversion.
463
    return (void*)malloc((uint32_t)size);
1 by brian
clean slate
464
  }
644 by Brian Aker
Clean up warnings for Solaris.
465
  static void operator delete(void* ptr_arg, size_t)
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) { }
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
502
  i_string_pair(const char* key_arg, const char* val_arg) :
1 by brian
clean slate
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(); }
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
573
  inline bool is_empty()        { return base_ilist::is_empty(); }
1 by brian
clean slate
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
1122.2.10 by Monty Taylor
Fixed all of the include guards.
623
#endif /* DRIZZLED_SQL_LIST_H */