1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 Sun Microsystems, Inc.
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.
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.
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
20
#ifndef DRIZZLED_SQL_LIST_H
21
#define DRIZZLED_SQL_LIST_H
27
#include <drizzled/memory/sql_alloc.h>
28
#include <drizzled/visibility.h>
32
typedef struct st_sql_list
44
inline void link_in_list(unsigned char *element,unsigned char **next_ptr)
51
inline void save_and_clear(struct st_sql_list *save)
56
inline void push_front(struct st_sql_list *save)
58
*save->next= first; /* link current list last */
60
elements+= save->elements;
62
inline void push_back(struct st_sql_list *save)
68
elements+= save->elements;
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
85
list_node - a node of a single-linked list.
86
@note We never call a destructor for instances of this class.
89
struct list_node : public memory::SqlAlloc
93
list_node(void *info_par,list_node *next_par)
94
:next(next_par),info(info_par)
96
list_node() /* For end_of_list */
104
extern DRIZZLED_API list_node end_of_list;
106
class base_list :public memory::SqlAlloc
109
list_node *first,**last;
114
inline void clear() { elements=0; first= &end_of_list; last=&first;}
115
inline base_list() { clear(); }
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
125
inline base_list(const base_list &tmp) :memory::SqlAlloc()
127
elements= tmp.elements;
129
last= elements ? tmp.last : &first;
131
inline base_list(bool) { }
132
inline bool push_back(void *info)
134
if (((*last)=new list_node(info, &end_of_list)))
136
last= &(*last)->next;
142
inline bool push_back(void *info, memory::Root *mem_root)
144
if (((*last)=new (mem_root) list_node(info, &end_of_list)))
146
last= &(*last)->next;
152
inline bool push_front(void *info)
154
list_node *node=new list_node(info,first);
165
void remove(list_node **prev)
167
list_node *node=(*prev)->next;
170
else if (last == &(*prev)->next)
175
inline void concat(base_list *list)
177
if (!list->is_empty())
181
elements+= list->elements;
184
inline void *pop(void)
186
if (first == &end_of_list) return 0;
187
list_node *tmp=first;
193
inline void disjoin(base_list *list)
195
list_node **prev= &first;
196
list_node *node= first;
197
list_node *list_first= list->first;
199
while (node && node != list_first)
208
inline void prepand(base_list *list)
210
if (!list->is_empty())
214
elements+= list->elements;
220
inline void swap(base_list &rhs)
222
std::swap(first, rhs.first);
223
std::swap(last, rhs.last);
224
std::swap(elements, rhs.elements);
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;
234
#ifdef LIST_EXTRA_DEBUG
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.
243
name Name to print to trace file
247
0 List invariants are not met.
250
bool check_list(const char *name)
252
base_list *list= this;
253
list_node *node= first;
256
while (node->next != &end_of_list)
265
if (last != &(node->next))
269
if (cnt+1 != elements)
275
#endif // LIST_EXTRA_DEBUG
278
void after(void *info,list_node *node)
280
list_node *new_node=new list_node(info,node->next);
283
if (last == &(node->next))
284
last= &new_node->next;
289
class base_list_iterator
293
list_node **el,**prev,*current;
295
void sublist(base_list &ls, uint32_t elm)
302
:list(0), el(0), prev(0), current(0)
305
base_list_iterator(base_list &list_par, list_node** el0)
306
:list(&list_par), el(el0), prev(0), current(0)
310
inline void *next(void)
315
return current->info;
317
inline void *replace(void *element)
318
{ // Return old element
319
void *tmp=current->info;
320
assert(current->info != 0);
321
current->info=element;
324
void *replace(base_list &new_list)
326
void *ret_value=current->info;
327
if (!new_list.is_empty())
329
*new_list.last=current->next;
330
current->info=new_list.first->info;
331
current->next=new_list.first->next;
332
if ((list->last == ¤t->next) && (new_list.elements > 1))
333
list->last= new_list.last;
334
list->elements+=new_list.elements-1;
336
return ret_value; // return old element
338
inline void remove(void) // Remove current
342
current=0; // Safeguard
344
void after(void *element) // Insert element after current
346
list->after(element,current);
347
current=current->next;
350
inline void **ref(void) // Get reference pointer
352
return ¤t->info;
354
inline bool is_last(void)
356
return el == &list->last_ref()->next;
360
template <class T> class List_iterator;
362
template <class T> class List :public base_list
365
typedef List_iterator<T> iterator;
367
friend class List_iterator<T>;
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)
384
list_node *element,*next;
385
for (element=first; element != &end_of_list; element=next)
388
delete (T*) element->info;
395
return iterator(*this, &first);
400
template <class T> class List_iterator :public base_list_iterator
403
List_iterator(List<T>& a, list_node** b) : base_list_iterator(a, b) {};
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(); }
412
Make a deep copy of each list element.
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
422
@return You must query the error state in Session for out-of-memory
423
situation after calling this function.
426
template <typename T>
427
void list_copy_and_replace_each_value(List<T> &list, memory::Root *mem_root)
429
/* Make a deep copy of each element */
430
typename List<T>::iterator it(list.begin());
433
it.replace(el->clone(mem_root));
436
} /* namespace drizzled */
438
#endif /* DRIZZLED_SQL_LIST_H */