The world's most popular open source database
00001 /* Copyright (C) 2000-2003 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 00018 #ifdef USE_PRAGMA_INTERFACE 00019 #pragma interface /* gcc class implementation */ 00020 #endif 00021 00022 /* mysql standard class memory allocator */ 00023 00024 class Sql_alloc 00025 { 00026 public: 00027 static void *operator new(size_t size) 00028 { 00029 return (void*) sql_alloc((uint) size); 00030 } 00031 static void *operator new[](size_t size) 00032 { 00033 return (void*) sql_alloc((uint) size); 00034 } 00035 static void *operator new[](size_t size, MEM_ROOT *mem_root) 00036 { return (void*) alloc_root(mem_root, (uint) size); } 00037 static void *operator new(size_t size, MEM_ROOT *mem_root) 00038 { return (void*) alloc_root(mem_root, (uint) size); } 00039 static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); } 00040 static void operator delete(void *ptr, MEM_ROOT *mem_root) 00041 { /* never called */ } 00042 static void operator delete[](void *ptr, size_t size) { TRASH(ptr, size); } 00043 #ifdef HAVE_purify 00044 bool dummy; 00045 inline Sql_alloc() :dummy(0) {} 00046 inline ~Sql_alloc() {} 00047 #else 00048 inline Sql_alloc() {} 00049 inline ~Sql_alloc() {} 00050 #endif 00051 00052 }; 00053 00054 00055 /* 00056 Basic single linked list 00057 Used for item and item_buffs. 00058 All list ends with a pointer to the 'end_of_list' element, which 00059 data pointer is a null pointer and the next pointer points to itself. 00060 This makes it very fast to traverse lists as we don't have to 00061 test for a specialend condition for list that can't contain a null 00062 pointer. 00063 */ 00064 00065 class list_node :public Sql_alloc 00066 { 00067 public: 00068 list_node *next; 00069 void *info; 00070 list_node(void *info_par,list_node *next_par) 00071 :next(next_par),info(info_par) 00072 {} 00073 list_node() /* For end_of_list */ 00074 { 00075 info=0; 00076 next= this; 00077 } 00078 friend class base_list; 00079 friend class base_list_iterator; 00080 }; 00081 00082 00083 extern list_node end_of_list; 00084 00085 class base_list :public Sql_alloc 00086 { 00087 protected: 00088 list_node *first,**last; 00089 00090 public: 00091 uint elements; 00092 00093 inline void empty() { elements=0; first= &end_of_list; last=&first;} 00094 inline base_list() { empty(); } 00095 inline base_list(const base_list &tmp) :Sql_alloc() 00096 { 00097 elements=tmp.elements; 00098 first=tmp.first; 00099 last=tmp.last; 00100 } 00101 inline base_list(bool error) { } 00102 inline bool push_back(void *info) 00103 { 00104 if (((*last)=new list_node(info, &end_of_list))) 00105 { 00106 last= &(*last)->next; 00107 elements++; 00108 return 0; 00109 } 00110 return 1; 00111 } 00112 inline bool push_back(void *info, MEM_ROOT *mem_root) 00113 { 00114 if (((*last)=new (mem_root) list_node(info, &end_of_list))) 00115 { 00116 last= &(*last)->next; 00117 elements++; 00118 return 0; 00119 } 00120 return 1; 00121 } 00122 inline bool push_front(void *info) 00123 { 00124 list_node *node=new list_node(info,first); 00125 if (node) 00126 { 00127 if (last == &first) 00128 last= &node->next; 00129 first=node; 00130 elements++; 00131 return 0; 00132 } 00133 return 1; 00134 } 00135 void remove(list_node **prev) 00136 { 00137 list_node *node=(*prev)->next; 00138 if (!--elements) 00139 last= &first; 00140 else if (last == &(*prev)->next) 00141 last= prev; 00142 delete *prev; 00143 *prev=node; 00144 } 00145 inline void concat(base_list *list) 00146 { 00147 if (!list->is_empty()) 00148 { 00149 *last= list->first; 00150 last= list->last; 00151 elements+= list->elements; 00152 } 00153 } 00154 inline void *pop(void) 00155 { 00156 if (first == &end_of_list) return 0; 00157 list_node *tmp=first; 00158 first=first->next; 00159 if (!--elements) 00160 last= &first; 00161 return tmp->info; 00162 } 00163 inline void disjoin(base_list *list) 00164 { 00165 list_node **prev= &first; 00166 list_node *node= first; 00167 list_node *list_first= list->first; 00168 elements=0; 00169 while (node && node != list_first) 00170 { 00171 prev= &node->next; 00172 node= node->next; 00173 elements++; 00174 } 00175 *prev= *last; 00176 last= prev; 00177 } 00178 inline void prepand(base_list *list) 00179 { 00180 if (!list->is_empty()) 00181 { 00182 *list->last= first; 00183 first= list->first; 00184 elements+= list->elements; 00185 } 00186 } 00187 inline list_node* last_node() { return *last; } 00188 inline list_node* first_node() { return first;} 00189 inline void *head() { return first->info; } 00190 inline void **head_ref() { return first != &end_of_list ? &first->info : 0; } 00191 inline bool is_empty() { return first == &end_of_list ; } 00192 inline list_node *last_ref() { return &end_of_list; } 00193 friend class base_list_iterator; 00194 friend class error_list; 00195 friend class error_list_iterator; 00196 00197 #ifdef LIST_EXTRA_DEBUG 00198 /* 00199 Check list invariants and print results into trace. Invariants are: 00200 - (*last) points to end_of_list 00201 - There are no NULLs in the list. 00202 - base_list::elements is the number of elements in the list. 00203 00204 SYNOPSIS 00205 check_list() 00206 name Name to print to trace file 00207 00208 RETURN 00209 1 The list is Ok. 00210 0 List invariants are not met. 00211 */ 00212 00213 bool check_list(const char *name) 00214 { 00215 base_list *list= this; 00216 list_node *node= first; 00217 uint cnt= 0; 00218 00219 while (node->next != &end_of_list) 00220 { 00221 if (!node->info) 00222 { 00223 DBUG_PRINT("list_invariants",("%s: error: NULL element in the list", 00224 name)); 00225 return FALSE; 00226 } 00227 node= node->next; 00228 cnt++; 00229 } 00230 if (last != &(node->next)) 00231 { 00232 DBUG_PRINT("list_invariants", ("%s: error: wrong last pointer", name)); 00233 return FALSE; 00234 } 00235 if (cnt+1 != elements) 00236 { 00237 DBUG_PRINT("list_invariants", ("%s: error: wrong element count", name)); 00238 return FALSE; 00239 } 00240 DBUG_PRINT("list_invariants", ("%s: list is ok", name)); 00241 return TRUE; 00242 } 00243 #endif // LIST_EXTRA_DEBUG 00244 00245 protected: 00246 void after(void *info,list_node *node) 00247 { 00248 list_node *new_node=new list_node(info,node->next); 00249 node->next=new_node; 00250 elements++; 00251 if (last == &(node->next)) 00252 last= &new_node->next; 00253 } 00254 }; 00255 00256 00257 class base_list_iterator 00258 { 00259 protected: 00260 base_list *list; 00261 list_node **el,**prev,*current; 00262 void sublist(base_list &ls, uint elm) 00263 { 00264 ls.first= *el; 00265 ls.last= list->last; 00266 ls.elements= elm; 00267 } 00268 public: 00269 base_list_iterator() 00270 :list(0), el(0), prev(0), current(0) 00271 {} 00272 00273 base_list_iterator(base_list &list_par) 00274 { init(list_par); } 00275 00276 inline void init(base_list &list_par) 00277 { 00278 list= &list_par; 00279 el= &list_par.first; 00280 prev= 0; 00281 current= 0; 00282 } 00283 00284 inline void *next(void) 00285 { 00286 prev=el; 00287 current= *el; 00288 el= ¤t->next; 00289 return current->info; 00290 } 00291 inline void *next_fast(void) 00292 { 00293 list_node *tmp; 00294 tmp= *el; 00295 el= &tmp->next; 00296 return tmp->info; 00297 } 00298 inline void rewind(void) 00299 { 00300 el= &list->first; 00301 } 00302 inline void *replace(void *element) 00303 { // Return old element 00304 void *tmp=current->info; 00305 DBUG_ASSERT(current->info != 0); 00306 current->info=element; 00307 return tmp; 00308 } 00309 void *replace(base_list &new_list) 00310 { 00311 void *ret_value=current->info; 00312 if (!new_list.is_empty()) 00313 { 00314 *new_list.last=current->next; 00315 current->info=new_list.first->info; 00316 current->next=new_list.first->next; 00317 if ((list->last == ¤t->next) && (new_list.elements > 1)) 00318 list->last= new_list.last; 00319 list->elements+=new_list.elements-1; 00320 } 00321 return ret_value; // return old element 00322 } 00323 inline void remove(void) // Remove current 00324 { 00325 list->remove(prev); 00326 el=prev; 00327 current=0; // Safeguard 00328 } 00329 void after(void *element) // Insert element after current 00330 { 00331 list->after(element,current); 00332 current=current->next; 00333 el= ¤t->next; 00334 } 00335 inline void **ref(void) // Get reference pointer 00336 { 00337 return ¤t->info; 00338 } 00339 inline bool is_last(void) 00340 { 00341 return el == &list->last_ref()->next; 00342 } 00343 friend class error_list_iterator; 00344 }; 00345 00346 template <class T> class List :public base_list 00347 { 00348 public: 00349 inline List() :base_list() {} 00350 inline List(const List<T> &tmp) :base_list(tmp) {} 00351 inline bool push_back(T *a) { return base_list::push_back(a); } 00352 inline bool push_back(T *a, MEM_ROOT *mem_root) 00353 { return base_list::push_back(a, mem_root); } 00354 inline bool push_front(T *a) { return base_list::push_front(a); } 00355 inline T* head() {return (T*) base_list::head(); } 00356 inline T** head_ref() {return (T**) base_list::head_ref(); } 00357 inline T* pop() {return (T*) base_list::pop(); } 00358 inline void concat(List<T> *list) { base_list::concat(list); } 00359 inline void disjoin(List<T> *list) { base_list::disjoin(list); } 00360 inline void prepand(List<T> *list) { base_list::prepand(list); } 00361 void delete_elements(void) 00362 { 00363 list_node *element,*next; 00364 for (element=first; element != &end_of_list; element=next) 00365 { 00366 next=element->next; 00367 delete (T*) element->info; 00368 } 00369 empty(); 00370 } 00371 }; 00372 00373 00374 template <class T> class List_iterator :public base_list_iterator 00375 { 00376 public: 00377 List_iterator(List<T> &a) : base_list_iterator(a) {} 00378 List_iterator() : base_list_iterator() {} 00379 inline void init(List<T> &a) { base_list_iterator::init(a); } 00380 inline T* operator++(int) { return (T*) base_list_iterator::next(); } 00381 inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); } 00382 inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); } 00383 inline void rewind(void) { base_list_iterator::rewind(); } 00384 inline void remove() { base_list_iterator::remove(); } 00385 inline void after(T *a) { base_list_iterator::after(a); } 00386 inline T** ref(void) { return (T**) base_list_iterator::ref(); } 00387 }; 00388 00389 00390 template <class T> class List_iterator_fast :public base_list_iterator 00391 { 00392 protected: 00393 inline T *replace(T *a) { return (T*) 0; } 00394 inline T *replace(List<T> &a) { return (T*) 0; } 00395 inline void remove(void) { } 00396 inline void after(T *a) { } 00397 inline T** ref(void) { return (T**) 0; } 00398 00399 public: 00400 inline List_iterator_fast(List<T> &a) : base_list_iterator(a) {} 00401 inline List_iterator_fast() : base_list_iterator() {} 00402 inline void init(List<T> &a) { base_list_iterator::init(a); } 00403 inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); } 00404 inline void rewind(void) { base_list_iterator::rewind(); } 00405 void sublist(List<T> &list_arg, uint el_arg) 00406 { 00407 base_list_iterator::sublist(list_arg, el_arg); 00408 } 00409 }; 00410 00411 00412 /* 00413 A simple intrusive list which automaticly removes element from list 00414 on delete (for THD element) 00415 */ 00416 00417 struct ilink 00418 { 00419 struct ilink **prev,*next; 00420 static void *operator new(size_t size) 00421 { 00422 return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE)); 00423 } 00424 static void operator delete(void* ptr_arg, size_t size) 00425 { 00426 my_free((gptr)ptr_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR)); 00427 } 00428 00429 inline ilink() 00430 { 00431 prev=0; next=0; 00432 } 00433 inline void unlink() 00434 { 00435 /* Extra tests because element doesn't have to be linked */ 00436 if (prev) *prev= next; 00437 if (next) next->prev=prev; 00438 prev=0 ; next=0; 00439 } 00440 virtual ~ilink() { unlink(); } /*lint -e1740 */ 00441 }; 00442 00443 00444 /* Needed to be able to have an I_List of char* strings in mysqld.cc. */ 00445 00446 class i_string: public ilink 00447 { 00448 public: 00449 const char* ptr; 00450 i_string():ptr(0) { } 00451 i_string(const char* s) : ptr(s) {} 00452 }; 00453 00454 /* needed for linked list of two strings for replicate-rewrite-db */ 00455 class i_string_pair: public ilink 00456 { 00457 public: 00458 const char* key; 00459 const char* val; 00460 i_string_pair():key(0),val(0) { } 00461 i_string_pair(const char* key_arg, const char* val_arg) : 00462 key(key_arg),val(val_arg) {} 00463 }; 00464 00465 00466 template <class T> class I_List_iterator; 00467 00468 /* 00469 WARNING: copy constructor of this class does not create a usable 00470 copy, as its members may point at each other. 00471 */ 00472 00473 class base_ilist 00474 { 00475 public: 00476 struct ilink *first,last; 00477 inline void empty() { first= &last; last.prev= &first; } 00478 base_ilist() { empty(); } 00479 inline bool is_empty() { return first == &last; } 00480 inline void append(ilink *a) 00481 { 00482 first->prev= &a->next; 00483 a->next=first; a->prev= &first; first=a; 00484 } 00485 inline void push_back(ilink *a) 00486 { 00487 *last.prev= a; 00488 a->next= &last; 00489 a->prev= last.prev; 00490 last.prev= &a->next; 00491 } 00492 inline struct ilink *get() 00493 { 00494 struct ilink *first_link=first; 00495 if (first_link == &last) 00496 return 0; 00497 first_link->unlink(); // Unlink from list 00498 return first_link; 00499 } 00500 inline struct ilink *head() 00501 { 00502 return (first != &last) ? first : 0; 00503 } 00504 friend class base_list_iterator; 00505 }; 00506 00507 00508 class base_ilist_iterator 00509 { 00510 base_ilist *list; 00511 struct ilink **el,*current; 00512 public: 00513 base_ilist_iterator(base_ilist &list_par) :list(&list_par), 00514 el(&list_par.first),current(0) {} 00515 void *next(void) 00516 { 00517 /* This is coded to allow push_back() while iterating */ 00518 current= *el; 00519 if (current == &list->last) return 0; 00520 el= ¤t->next; 00521 return current; 00522 } 00523 }; 00524 00525 00526 template <class T> 00527 class I_List :private base_ilist 00528 { 00529 public: 00530 I_List() :base_ilist() {} 00531 inline void empty() { base_ilist::empty(); } 00532 inline bool is_empty() { return base_ilist::is_empty(); } 00533 inline void append(T* a) { base_ilist::append(a); } 00534 inline void push_back(T* a) { base_ilist::push_back(a); } 00535 inline T* get() { return (T*) base_ilist::get(); } 00536 inline T* head() { return (T*) base_ilist::head(); } 00537 #ifndef _lint 00538 friend class I_List_iterator<T>; 00539 #endif 00540 }; 00541 00542 00543 template <class T> class I_List_iterator :public base_ilist_iterator 00544 { 00545 public: 00546 I_List_iterator(I_List<T> &a) : base_ilist_iterator(a) {} 00547 inline T* operator++(int) { return (T*) base_ilist_iterator::next(); } 00548 };
1.4.7

