diff options
Diffstat (limited to 'sql/sql_list.h')
-rw-r--r-- | sql/sql_list.h | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/sql/sql_list.h b/sql/sql_list.h new file mode 100644 index 00000000000..725d506e62a --- /dev/null +++ b/sql/sql_list.h @@ -0,0 +1,310 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +/* mysql standard open memoryallocator */ + +#ifdef __GNUC__ +#pragma interface /* gcc class implementation */ +#endif + + +class Sql_alloc +{ +public: + static void *operator new(size_t size) {return (void*) sql_alloc(size); } + static void operator delete(void *ptr, size_t size) {} /*lint -e715 */ + inline Sql_alloc() {}; + inline ~Sql_alloc() {}; +}; + +/* +** basic single linked list +** Used for item and item_buffs. +*/ + +class base_list :public Sql_alloc { +protected: + class list_node :public Sql_alloc + { + public: + list_node *next; + void *info; + list_node(void *info_par,list_node *next_par) : next(next_par),info(info_par) {} + friend class base_list; + friend class base_list_iterator; + }; + list_node *first,**last; + +public: + uint elements; + + inline void empty() { elements=0; first=0; last=&first;} + inline base_list() { empty(); } + inline base_list(const base_list &tmp) :Sql_alloc() + { + elements=tmp.elements; + first=tmp.first; + last=tmp.last; + } + inline bool push_back(void *info) + { + if (((*last)=new list_node(info,0))) + { + last= &(*last)->next; + elements++; + return 0; + } + return 1; + } + inline bool push_front(void *info) + { + list_node *node=new list_node(info,first); + if (node) + { + if (!first) + last= &node->next; + first=node; + elements++; + return 0; + } + return 1; + } + void remove(list_node **prev) + { + list_node *node=(*prev)->next; + delete *prev; + *prev=node; + if (!--elements) + { + last= &first; + first=0; + } + } + inline void *pop(void) + { + if (!first) return 0; + list_node *tmp=first; + first=first->next; + if (!--elements) + last= &first; + return tmp->info; + } + inline void *head() { return first ? first->info : 0; } + inline void **head_ref() { return first ? &first->info : 0; } + friend class base_list_iterator; + +protected: + void after(void *info,list_node *node) + { + list_node *new_node=new list_node(info,node->next); + node->next=new_node; + elements++; + if (last == &(node->next)) + last= &new_node->next; + } +}; + + +class base_list_iterator +{ + base_list *list; + base_list::list_node **el,**prev,*current; +public: + base_list_iterator(base_list &list_par) :list(&list_par),el(&list_par.first), + prev(0),current(0) + {} + inline void *next(void) + { + prev=el; + if (!(current= *el)) + return 0; + el= ¤t->next; + return current->info; + } + inline void rewind(void) + { + el= &list->first; + } + void *replace(void *element) + { // Return old element + void *tmp=current->info; + current->info=element; + return tmp; + } + void *replace(base_list &new_list) + { + void *ret_value=current->info; + if (new_list.first) + { + *new_list.last=current->next; + current->info=new_list.first->info; + current->next=new_list.first->next; + list->elements+=new_list.elements-1; + } + return ret_value; // return old element + } + inline void remove(void) // Remove current + { + list->remove(prev); + el=prev; + current=0; // Safeguard + } + void after(void *element) // Insert element after current + { + list->after(element,current); + current=current->next; + el= ¤t->next; + } + inline void **ref(void) // Get reference pointer + { + return ¤t->info; + } + inline bool is_last(void) + { + return *el == 0; + } +}; + + +template <class T> class List :public base_list +{ +public: + inline List() :base_list() {} + inline List(const List<T> &tmp) :base_list(tmp) {} + inline bool push_back(T *a) { return base_list::push_back(a); } + inline bool push_front(T *a) { return base_list::push_front(a); } + inline T* head() {return (T*) base_list::head(); } + inline T** head_ref() {return (T**) base_list::head_ref(); } + inline T* pop() {return (T*) base_list::pop(); } + void delete_elements(void) + { + list_node *element,*next; + for (element=first; element ; element=next) + { + next=element->next; + delete (T*) element->info; + } + empty(); + } +}; + + +template <class T> class List_iterator :public base_list_iterator +{ +public: + List_iterator(List<T> &a) : base_list_iterator(a) {} + inline T* operator++(int) { return (T*) base_list_iterator::next(); } + inline void rewind(void) { base_list_iterator::rewind(); } + inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); } + inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); } + inline void remove(void) { base_list_iterator::remove(); } + inline void after(T *a) { base_list_iterator::after(a); } + inline T** ref(void) { return (T**) base_list_iterator::ref(); } + inline bool is_last(void) { return base_list_iterator::is_last(); } +}; + + +/* +** An simple intrusive list with automaticly removes element from list +** on delete (for THD element) +*/ + +struct ilink { + struct ilink **prev,*next; + inline ilink() + { + prev=0; next=0; + } + inline void unlink() + { + /* Extra tests because element doesn't have to be linked */ + if (prev) *prev= next; + if (next) next->prev=prev; + prev=0 ; next=0; + } + virtual ~ilink() { unlink(); } /*lint -e1740 */ +}; + +template <class T> class I_List_iterator; + +class base_ilist { + public: + struct ilink *first,last; + base_ilist() { first= &last; last.prev= &first; } + inline bool is_empty() { return first == &last; } + inline void append(ilink *a) + { + first->prev= &a->next; + a->next=first; a->prev= &first; first=a; + } + inline void push_back(ilink *a) + { + *last.prev= a; + a->next= &last; + a->prev= last.prev; + last.prev= &a->next; + } + inline struct ilink *get() + { + struct ilink *first_link=first; + if (first_link == &last) + return 0; + first_link->unlink(); // Unlink from list + return first_link; + } + friend class base_list_iterator; +}; + + +class base_ilist_iterator +{ + base_ilist *list; + struct ilink **el,*current; +public: + base_ilist_iterator(base_ilist &list_par) :list(&list_par), + el(&list_par.first),current(0) {} + void *next(void) + { + /* This is coded to allow push_back() while iterating */ + current= *el; + if (current == &list->last) return 0; + el= ¤t->next; + return current; + } +}; + + +template <class T> +class I_List :private base_ilist { +public: + I_List() :base_ilist() {} + inline bool is_empty() { return base_ilist::is_empty(); } + inline void append(T* a) { base_ilist::append(a); } + inline void push_back(T* a) { base_ilist::push_back(a); } + inline T* get() { return (T*) base_ilist::get(); } +#ifndef _lint + friend class I_List_iterator<T>; +#endif +}; + + +template <class T> class I_List_iterator :public base_ilist_iterator +{ +public: + I_List_iterator(I_List<T> &a) : base_ilist_iterator(a) {} + inline T* operator++(int) { return (T*) base_ilist_iterator::next(); } +}; |