Drizzled Public API Documentation

sql_list.h
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 #pragma once
00021 
00022 #include <cstdlib>
00023 #include <cassert>
00024 #include <utility>
00025 #include <algorithm>
00026 #include <drizzled/memory/sql_alloc.h>
00027 #include <drizzled/visibility.h>
00028 
00029 namespace drizzled {
00030 
00031 struct SQL_LIST 
00032 {
00033   uint32_t elements;
00034   unsigned char *first;
00035   unsigned char **next;
00036 
00037   void clear()
00038   {
00039     elements=0;
00040     first=0;
00041     next= &first;
00042   }
00043 
00044   size_t size() const
00045   {
00046     return elements;
00047   }
00048 
00049   void link_in_list(unsigned char *element,unsigned char **next_ptr)
00050   {
00051     elements++;
00052     (*next)=element;
00053     next= next_ptr;
00054     *next=0;
00055   }
00056   void save_and_clear(SQL_LIST *save)
00057   {
00058     *save= *this;
00059     clear();
00060   }
00061   void push_front(SQL_LIST *save)
00062   {
00063     *save->next= first;       /* link current list last */
00064     first= save->first;
00065     elements+= save->elements;
00066   }
00067   void push_back(SQL_LIST *save)
00068   {
00069     if (save->first)
00070     {
00071       *next= save->first;
00072       next= save->next;
00073       elements+= save->elements;
00074     }
00075   }
00076 };
00077 
00078 /*
00079   Basic single linked list
00080   Used for item and item_buffs.
00081   All list ends with a pointer to the 'end_of_list' element, which
00082   data pointer is a null pointer and the next pointer points to itself.
00083   This makes it very fast to traverse lists as we don't have to
00084   test for a specialend condition for list that can't contain a null
00085   pointer.
00086 */
00087 
00088 
00094 struct list_node : public memory::SqlAlloc
00095 {
00096   list_node *next;
00097   void *info;
00098   list_node(void *info_par,list_node *next_par)
00099     :next(next_par),info(info_par)
00100   {}
00101   list_node()         /* For end_of_list */
00102   {
00103     info= 0;
00104     next= this;
00105   }
00106 };
00107 
00108 extern DRIZZLED_API list_node end_of_list;
00109 
00110 class base_list :public memory::SqlAlloc
00111 {
00112 protected:
00113   list_node *first,**last;
00114   uint32_t elements;
00115 public:
00116 
00117   void clear() { elements=0; first= &end_of_list; last=&first;}
00118   base_list() { clear(); }
00128   base_list(const base_list &tmp) :memory::SqlAlloc()
00129   {
00130     elements= tmp.elements;
00131     first= tmp.first;
00132     last= elements ? tmp.last : &first;
00133   }
00134   base_list(bool) { }
00135   void push_back(void *info)
00136   {
00137     *last = new list_node(info, &end_of_list);
00138     last= &(*last)->next;
00139     elements++;
00140   }
00141   void push_back(void *info, memory::Root& mem)
00142   {
00143     *last = new (mem) list_node(info, &end_of_list);
00144     last= &(*last)->next;
00145     elements++;
00146   }
00147   void push_front(void *info)
00148   {
00149     list_node *node=new list_node(info,first);
00150     if (last == &first)
00151       last= &node->next;
00152       first=node;
00153       elements++;
00154   }
00155   void remove(list_node **prev)
00156   {
00157     list_node *node=(*prev)->next;
00158     if (!--elements)
00159       last= &first;
00160     else if (last == &(*prev)->next)
00161       last= prev;
00162     delete *prev;
00163     *prev=node;
00164   }
00165   void concat(base_list *list)
00166   {
00167     if (!list->is_empty())
00168     {
00169       *last= list->first;
00170       last= list->last;
00171       elements+= list->elements;
00172     }
00173   }
00174   void *pop()
00175   {
00176     if (first == &end_of_list) return 0;
00177     list_node *tmp=first;
00178     first=first->next;
00179     if (!--elements)
00180       last= &first;
00181     return tmp->info;
00182   }
00183   void disjoin(base_list *list)
00184   {
00185     list_node **prev= &first;
00186     list_node *node= first;
00187     list_node *list_first= list->first;
00188     elements=0;
00189     while (node && node != list_first)
00190     {
00191       prev= &node->next;
00192       node= node->next;
00193       elements++;
00194     }
00195     *prev= *last;
00196     last= prev;
00197   }
00198   void prepand(base_list *list)
00199   {
00200     if (!list->is_empty())
00201     {
00202       *list->last= first;
00203       first= list->first;
00204       elements+= list->elements;
00205     }
00206   }
00210   void swap(base_list &rhs)
00211   {
00212     std::swap(first, rhs.first);
00213     std::swap(last, rhs.last);
00214     std::swap(elements, rhs.elements);
00215   }
00216   bool is_empty() { return first == &end_of_list ; }
00217   friend class base_list_iterator;
00218 
00219 #ifdef LIST_EXTRA_DEBUG
00220   /*
00221     Check list invariants and print results into trace. Invariants are:
00222       - (*last) points to end_of_list
00223       - There are no NULLs in the list.
00224       - base_list::elements is the number of elements in the list.
00225 
00226     SYNOPSIS
00227       check_list()
00228         name  Name to print to trace file
00229 
00230     RETURN
00231       1  The list is Ok.
00232       0  List invariants are not met.
00233   */
00234 
00235   bool check_list(const char *name)
00236   {
00237     list_node *node= first;
00238     uint32_t cnt= 0;
00239 
00240     while (node->next != &end_of_list)
00241     {
00242       if (!node->info)
00243       {
00244         return false;
00245       }
00246       node= node->next;
00247       cnt++;
00248     }
00249     if (last != &(node->next))
00250     {
00251       return false;
00252     }
00253     if (cnt+1 != elements)
00254     {
00255       return false;
00256     }
00257     return true;
00258   }
00259 #endif // LIST_EXTRA_DEBUG
00260 
00261 protected:
00262   void after(void *info,list_node *node)
00263   {
00264     list_node *new_node=new list_node(info,node->next);
00265     node->next=new_node;
00266     elements++;
00267     if (last == &(node->next))
00268       last= &new_node->next;
00269   }
00270 };
00271 
00272 
00273 class base_list_iterator
00274 {
00275 protected:
00276   base_list *list;
00277   list_node **el,**prev,*current;
00278 public:
00279   void sublist(base_list &ls, uint32_t elm) const
00280   {
00281     ls.first= *el;
00282     ls.last= list->last;
00283     ls.elements= elm;
00284   }
00285   base_list_iterator()
00286     :list(0), el(0), prev(0), current(0)
00287   {}
00288 
00289   base_list_iterator(base_list &list_par, list_node** el0)
00290     :list(&list_par), el(el0), prev(0), current(0)
00291   {
00292   }
00293 
00294   void *replace(base_list &new_list)
00295   {
00296     void *ret_value=current->info;
00297     if (!new_list.is_empty())
00298     {
00299       *new_list.last=current->next;
00300       current->info=new_list.first->info;
00301       current->next=new_list.first->next;
00302       if (list->last == &current->next && new_list.elements > 1)
00303         list->last= new_list.last;
00304       list->elements+=new_list.elements-1;
00305     }
00306     return ret_value;       // return old element
00307   }
00308   void remove()     // Remove current
00309   {
00310     list->remove(prev);
00311     el=prev;
00312     current=0;          // Safeguard
00313   }
00314   void after(void *element)     // Insert element after current
00315   {
00316     list->after(element,current);
00317     current=current->next;
00318     el= &current->next;
00319   }
00320 };
00321 
00322 template <class T> class List_iterator;
00323 
00324 template <class T> class List : public base_list
00325 {
00326 public:
00327   typedef List_iterator<T> iterator;
00328 
00329   friend class List_iterator<T>;
00330 
00331   List() {}
00332   List(const List<T> &tmp) : base_list(tmp) {}
00333   List(const List<T> &tmp, memory::Root *mem_root) : base_list(tmp, mem_root) {}
00334   T& front() {return *static_cast<T*>(first->info); }
00335   T* pop()  {return static_cast<T*>(base_list::pop()); }
00336   void concat(List<T> *list) { base_list::concat(list); }
00337   void disjoin(List<T> *list) { base_list::disjoin(list); }
00338   void prepand(List<T> *list) { base_list::prepand(list); }
00339   void delete_elements()
00340   {
00341     list_node *element,*next;
00342     for (element=first; element != &end_of_list; element=next)
00343     {
00344       next=element->next;
00345       delete (T*) element->info;
00346     }
00347     clear();
00348   }
00349 
00350   iterator begin()
00351   {
00352     return iterator(*this, &first);
00353   }
00354 
00355   size_t size() const
00356   {
00357     return elements;
00358   }
00359 
00360   void set_size(size_t v)
00361   {
00362     elements = v;
00363   }
00364 };
00365 
00366 template <class T> class List_iterator : public base_list_iterator
00367 {
00368 public:
00369   List_iterator(List<T>& a, list_node** b) : base_list_iterator(a, b) {};
00370   List_iterator() {};
00371   T *operator++(int) { prev=el; current= *el; el= &current->next; return (T*)current->info; }
00372   T *replace(T *a)   { T* old = (T*) current->info; current->info= a; return old; }
00373   void replace(List<T> &a) { base_list_iterator::replace(a); }
00374   T** ref() { return (T**) &current->info; }
00375 
00376   T& operator*()
00377   {
00378     return *(T*)current->info;
00379   }
00380 
00381   T* operator->()
00382   {
00383     return (T*)current->info;
00384   }
00385 };
00386 
00387 } /* namespace drizzled */
00388