~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_list.h

  • Committer: Monty Taylor
  • Date: 2008-08-01 22:33:44 UTC
  • mto: (236.1.42 codestyle)
  • mto: This revision was merged to the branch mainline in revision 261.
  • Revision ID: monty@inaugust.com-20080801223344-vzhlflfmtijp1imv
First pass at gettexizing the error messages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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, Inc.
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
 
 
20
 
#ifndef DRIZZLED_SQL_LIST_H
21
 
#define DRIZZLED_SQL_LIST_H
22
 
 
23
 
#include <cstdlib>
24
 
#include <cassert>
25
 
#include <utility>
26
 
#include <algorithm>
27
 
#include <drizzled/memory/sql_alloc.h>
28
 
#include <drizzled/visibility.h>
29
 
 
30
 
namespace drizzled {
31
 
 
32
 
typedef struct st_sql_list 
33
 
{
34
 
  uint32_t elements;
35
 
  unsigned char *first;
36
 
  unsigned char **next;
37
 
 
38
 
  inline void clear()
39
 
  {
40
 
    elements=0;
41
 
    first=0;
42
 
    next= &first;
43
 
  }
44
 
  inline void link_in_list(unsigned char *element,unsigned char **next_ptr)
45
 
  {
46
 
    elements++;
47
 
    (*next)=element;
48
 
    next= next_ptr;
49
 
    *next=0;
50
 
  }
51
 
  inline void save_and_clear(struct st_sql_list *save)
52
 
  {
53
 
    *save= *this;
54
 
    clear();
55
 
  }
56
 
  inline void push_front(struct st_sql_list *save)
57
 
  {
58
 
    *save->next= first;                         /* link current list last */
59
 
    first= save->first;
60
 
    elements+= save->elements;
61
 
  }
62
 
  inline void push_back(struct st_sql_list *save)
63
 
  {
64
 
    if (save->first)
65
 
    {
66
 
      *next= save->first;
67
 
      next= save->next;
68
 
      elements+= save->elements;
69
 
    }
70
 
  }
71
 
} SQL_LIST;
72
 
 
73
 
/*
74
 
  Basic single linked list
75
 
  Used for item and item_buffs.
76
 
  All list ends with a pointer to the 'end_of_list' element, which
77
 
  data pointer is a null pointer and the next pointer points to itself.
78
 
  This makes it very fast to traverse lists as we don't have to
79
 
  test for a specialend condition for list that can't contain a null
80
 
  pointer.
81
 
*/
82
 
 
83
 
 
84
 
/**
85
 
  list_node - a node of a single-linked list.
86
 
  @note We never call a destructor for instances of this class.
87
 
*/
88
 
 
89
 
struct list_node : public memory::SqlAlloc
90
 
{
91
 
  list_node *next;
92
 
  void *info;
93
 
  list_node(void *info_par,list_node *next_par)
94
 
    :next(next_par),info(info_par)
95
 
  {}
96
 
  list_node()                                   /* For end_of_list */
97
 
  {
98
 
    info= 0;
99
 
    next= this;
100
 
  }
101
 
};
102
 
 
103
 
 
104
 
extern DRIZZLED_API list_node end_of_list;
105
 
 
106
 
class base_list :public memory::SqlAlloc
107
 
{
108
 
protected:
109
 
  list_node *first,**last;
110
 
 
111
 
public:
112
 
  uint32_t elements;
113
 
 
114
 
  inline void clear() { elements=0; first= &end_of_list; last=&first;}
115
 
  inline base_list() { clear(); }
116
 
  /**
117
 
    This is a shallow copy constructor that implicitly passes the ownership
118
 
    from the source list to the new instance. The old instance is not
119
 
    updated, so both objects end up sharing the same nodes. If one of
120
 
    the instances then adds or removes a node, the other becomes out of
121
 
    sync ('last' pointer), while still operational. Some old code uses and
122
 
    relies on this behaviour. This logic is quite tricky: please do not use
123
 
    it in any new code.
124
 
  */
125
 
  inline base_list(const base_list &tmp) :memory::SqlAlloc()
126
 
  {
127
 
    elements= tmp.elements;
128
 
    first= tmp.first;
129
 
    last= elements ? tmp.last : &first;
130
 
  }
131
 
  inline base_list(bool) { }
132
 
  inline bool push_back(void *info)
133
 
  {
134
 
    if (((*last)=new list_node(info, &end_of_list)))
135
 
    {
136
 
      last= &(*last)->next;
137
 
      elements++;
138
 
      return 0;
139
 
    }
140
 
    return 1;
141
 
  }
142
 
  inline bool push_back(void *info, memory::Root *mem_root)
143
 
  {
144
 
    if (((*last)=new (mem_root) list_node(info, &end_of_list)))
145
 
    {
146
 
      last= &(*last)->next;
147
 
      elements++;
148
 
      return 0;
149
 
    }
150
 
    return 1;
151
 
  }
152
 
  inline bool push_front(void *info)
153
 
  {
154
 
    list_node *node=new list_node(info,first);
155
 
    if (node)
156
 
    {
157
 
      if (last == &first)
158
 
        last= &node->next;
159
 
      first=node;
160
 
      elements++;
161
 
      return 0;
162
 
    }
163
 
    return 1;
164
 
  }
165
 
  void remove(list_node **prev)
166
 
  {
167
 
    list_node *node=(*prev)->next;
168
 
    if (!--elements)
169
 
      last= &first;
170
 
    else if (last == &(*prev)->next)
171
 
      last= prev;
172
 
    delete *prev;
173
 
    *prev=node;
174
 
  }
175
 
  inline void concat(base_list *list)
176
 
  {
177
 
    if (!list->is_empty())
178
 
    {
179
 
      *last= list->first;
180
 
      last= list->last;
181
 
      elements+= list->elements;
182
 
    }
183
 
  }
184
 
  inline void *pop(void)
185
 
  {
186
 
    if (first == &end_of_list) return 0;
187
 
    list_node *tmp=first;
188
 
    first=first->next;
189
 
    if (!--elements)
190
 
      last= &first;
191
 
    return tmp->info;
192
 
  }
193
 
  inline void disjoin(base_list *list)
194
 
  {
195
 
    list_node **prev= &first;
196
 
    list_node *node= first;
197
 
    list_node *list_first= list->first;
198
 
    elements=0;
199
 
    while (node && node != list_first)
200
 
    {
201
 
      prev= &node->next;
202
 
      node= node->next;
203
 
      elements++;
204
 
    }
205
 
    *prev= *last;
206
 
    last= prev;
207
 
  }
208
 
  inline void prepand(base_list *list)
209
 
  {
210
 
    if (!list->is_empty())
211
 
    {
212
 
      *list->last= first;
213
 
      first= list->first;
214
 
      elements+= list->elements;
215
 
    }
216
 
  }
217
 
  /**
218
 
    Swap two lists.
219
 
  */
220
 
  inline void swap(base_list &rhs)
221
 
  {
222
 
    std::swap(first, rhs.first);
223
 
    std::swap(last, rhs.last);
224
 
    std::swap(elements, rhs.elements);
225
 
  }
226
 
  inline list_node* last_node() { return *last; }
227
 
  inline list_node* first_node() { return first;}
228
 
  inline void *head() { return first->info; }
229
 
  inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
230
 
  inline bool is_empty() { return first == &end_of_list ; }
231
 
  inline list_node *last_ref() { return &end_of_list; }
232
 
  friend class base_list_iterator;
233
 
 
234
 
#ifdef LIST_EXTRA_DEBUG
235
 
  /*
236
 
    Check list invariants and print results into trace. Invariants are:
237
 
      - (*last) points to end_of_list
238
 
      - There are no NULLs in the list.
239
 
      - base_list::elements is the number of elements in the list.
240
 
 
241
 
    SYNOPSIS
242
 
      check_list()
243
 
        name  Name to print to trace file
244
 
 
245
 
    RETURN
246
 
      1  The list is Ok.
247
 
      0  List invariants are not met.
248
 
  */
249
 
 
250
 
  bool check_list(const char *name)
251
 
  {
252
 
    base_list *list= this;
253
 
    list_node *node= first;
254
 
    uint32_t cnt= 0;
255
 
 
256
 
    while (node->next != &end_of_list)
257
 
    {
258
 
      if (!node->info)
259
 
      {
260
 
        return false;
261
 
      }
262
 
      node= node->next;
263
 
      cnt++;
264
 
    }
265
 
    if (last != &(node->next))
266
 
    {
267
 
      return false;
268
 
    }
269
 
    if (cnt+1 != elements)
270
 
    {
271
 
      return false;
272
 
    }
273
 
    return true;
274
 
  }
275
 
#endif // LIST_EXTRA_DEBUG
276
 
 
277
 
protected:
278
 
  void after(void *info,list_node *node)
279
 
  {
280
 
    list_node *new_node=new list_node(info,node->next);
281
 
    node->next=new_node;
282
 
    elements++;
283
 
    if (last == &(node->next))
284
 
      last= &new_node->next;
285
 
  }
286
 
};
287
 
 
288
 
 
289
 
class base_list_iterator
290
 
{
291
 
protected:
292
 
  base_list *list;
293
 
  list_node **el,**prev,*current;
294
 
public:
295
 
  void sublist(base_list &ls, uint32_t elm)
296
 
  {
297
 
    ls.first= *el;
298
 
    ls.last= list->last;
299
 
    ls.elements= elm;
300
 
  }
301
 
  base_list_iterator()
302
 
    :list(0), el(0), prev(0), current(0)
303
 
  {}
304
 
 
305
 
  base_list_iterator(base_list &list_par, list_node** el0)
306
 
    :list(&list_par), el(el0), prev(0), current(0)
307
 
  {
308
 
  }
309
 
 
310
 
  inline void *next(void)
311
 
  {
312
 
    prev=el;
313
 
    current= *el;
314
 
    el= &current->next;
315
 
    return current->info;
316
 
  }
317
 
  inline void *replace(void *element)
318
 
  {                                             // Return old element
319
 
    void *tmp=current->info;
320
 
    assert(current->info != 0);
321
 
    current->info=element;
322
 
    return tmp;
323
 
  }
324
 
  void *replace(base_list &new_list)
325
 
  {
326
 
    void *ret_value=current->info;
327
 
    if (!new_list.is_empty())
328
 
    {
329
 
      *new_list.last=current->next;
330
 
      current->info=new_list.first->info;
331
 
      current->next=new_list.first->next;
332
 
      if ((list->last == &current->next) && (new_list.elements > 1))
333
 
        list->last= new_list.last;
334
 
      list->elements+=new_list.elements-1;
335
 
    }
336
 
    return ret_value;                           // return old element
337
 
  }
338
 
  inline void remove(void)                      // Remove current
339
 
  {
340
 
    list->remove(prev);
341
 
    el=prev;
342
 
    current=0;                                  // Safeguard
343
 
  }
344
 
  void after(void *element)                     // Insert element after current
345
 
  {
346
 
    list->after(element,current);
347
 
    current=current->next;
348
 
    el= &current->next;
349
 
  }
350
 
  inline void **ref(void)                       // Get reference pointer
351
 
  {
352
 
    return &current->info;
353
 
  }
354
 
  inline bool is_last(void)
355
 
  {
356
 
    return el == &list->last_ref()->next;
357
 
  }
358
 
};
359
 
 
360
 
template <class T> class List_iterator;
361
 
 
362
 
template <class T> class List :public base_list
363
 
{
364
 
public:
365
 
  typedef List_iterator<T> iterator;
366
 
 
367
 
  friend class List_iterator<T>;
368
 
 
369
 
  inline List() :base_list() {}
370
 
  inline List(const List<T> &tmp) :base_list(tmp) {}
371
 
  inline List(const List<T> &tmp, memory::Root *mem_root) :
372
 
    base_list(tmp, mem_root) {}
373
 
  inline bool push_back(T *a) { return base_list::push_back(a); }
374
 
  inline bool push_back(T *a, memory::Root *mem_root)
375
 
  { return base_list::push_back(a, mem_root); }
376
 
  inline bool push_front(T *a) { return base_list::push_front(a); }
377
 
  inline T* head() {return static_cast<T*>(base_list::head()); }
378
 
  inline T* pop()  {return static_cast<T*>(base_list::pop()); }
379
 
  inline void concat(List<T> *list) { base_list::concat(list); }
380
 
  inline void disjoin(List<T> *list) { base_list::disjoin(list); }
381
 
  inline void prepand(List<T> *list) { base_list::prepand(list); }
382
 
  void delete_elements(void)
383
 
  {
384
 
    list_node *element,*next;
385
 
    for (element=first; element != &end_of_list; element=next)
386
 
    {
387
 
      next=element->next;
388
 
      delete (T*) element->info;
389
 
    }
390
 
    clear();
391
 
  }
392
 
 
393
 
  iterator begin()
394
 
  {
395
 
    return iterator(*this, &first);
396
 
  }
397
 
};
398
 
 
399
 
 
400
 
template <class T> class List_iterator :public base_list_iterator
401
 
{
402
 
public:
403
 
  List_iterator(List<T>& a, list_node** b) : base_list_iterator(a, b) {};
404
 
  List_iterator() {};
405
 
  inline T* operator++(int) { return (T*) base_list_iterator::next(); }
406
 
  inline T *replace(T *a)   { return (T*) base_list_iterator::replace(a); }
407
 
  inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
408
 
  inline T** ref(void)      { return (T**) base_list_iterator::ref(); }
409
 
};
410
 
 
411
 
/**
412
 
  Make a deep copy of each list element.
413
 
 
414
 
  @note A template function and not a template method of class List
415
 
  is employed because of explicit template instantiation:
416
 
  in server code there are explicit instantiations of List<T> and
417
 
  an explicit instantiation of a template requires that any method
418
 
  of the instantiated class used in the template can be resolved.
419
 
  Evidently not all template arguments have clone() method with
420
 
  the right signature.
421
 
 
422
 
  @return You must query the error state in Session for out-of-memory
423
 
  situation after calling this function.
424
 
*/
425
 
 
426
 
template <typename T>
427
 
void list_copy_and_replace_each_value(List<T> &list, memory::Root *mem_root)
428
 
{
429
 
  /* Make a deep copy of each element */
430
 
  typename List<T>::iterator it(list.begin());
431
 
  T *el;
432
 
  while ((el= it++))
433
 
    it.replace(el->clone(mem_root));
434
 
}
435
 
 
436
 
} /* namespace drizzled */
437
 
 
438
 
#endif /* DRIZZLED_SQL_LIST_H */