int.Vec.cc

Go to the documentation of this file.
00001 // This may look like C code, but it is really -*- C++ -*-
00002 /* 
00003 Copyright (C) 1988 Free Software Foundation
00004     written by Doug Lea (dl@rocky.oswego.edu)
00005 
00006 This file is part of the GNU C++ Library.  This library is free
00007 software; you can redistribute it and/or modify it under the terms of
00008 the GNU Library General Public License as published by the Free
00009 Software Foundation; either version 2 of the License, or (at your
00010 option) any later version.  This library is distributed in the hope
00011 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00012 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00013 PURPOSE.  See the GNU Library General Public License for more details.
00014 You should have received a copy of the GNU Library General Public
00015 License along with this library; if not, write to the Free Software
00016 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 
00018 Linking this file statically or dynamically with other modules is making
00019 a combined work based on this file.  Thus, the terms and conditions of
00020 the GNU General Public License cover the whole combination.
00021 
00022 In addition, as a special exception, the copyright holders of this file
00023 give you permission to combine this file with free software programs or
00024 libraries that are released under the GNU LGPL and with code included in
00025 the standard release of ns-2 under the Apache 2.0 license or under
00026 otherwise-compatible licenses with advertising requirements (or modified
00027 versions of such code, with unchanged license).  You may copy and
00028 distribute such a system following the terms of the GNU GPL for this
00029 file and the licenses of the other code concerned, provided that you
00030 include the source code of that other code when and as the GNU GPL
00031 requires distribution of source code.
00032 
00033 Note that people who make modified versions of this file are not
00034 obligated to grant this special exception for their modified versions;
00035 it is their choice whether to do so.  The GNU General Public License
00036 gives permission to release a modified version without this exception;
00037 this exception also makes it possible to release a modified version
00038 which carries forward this exception.
00039 */
00040 
00041 #ifdef __GNUG__
00042 #pragma implementation
00043 #endif
00044 // #include <stream.h>
00045 #include <stdlib.h>
00046 #include "lib/builtin.h"
00047 #include "lib/int.Vec.h"
00048 
00049 // error handling
00050 
00051 
00052 void default_intVec_error_handler(const char* msg)
00053 {
00054 #if 0
00055   cerr << "Fatal intVec error. " << msg << "\n";
00056 #else
00057   // ns doesn't use streams
00058   fprintf(stderr, "Fatal intVec error. %s\n", msg);
00059 #endif
00060   exit(1);
00061 }
00062 
00063 one_arg_error_handler_t intVec_error_handler = default_intVec_error_handler;
00064 
00065 one_arg_error_handler_t set_intVec_error_handler(one_arg_error_handler_t f)
00066 {
00067   one_arg_error_handler_t old = intVec_error_handler;
00068   intVec_error_handler = f;
00069   return old;
00070 }
00071 
00072 void intVec::error(const char* msg)
00073 {
00074   (*intVec_error_handler)(msg);
00075 }
00076 
00077 void intVec::range_error()
00078 {
00079   (*intVec_error_handler)("Index out of range.");
00080 }
00081 
00082 intVec::intVec(const intVec& v)
00083 {
00084   s = new int [len = v.len];
00085   int* top = &(s[len]);
00086   int* t = s;
00087   const int* u = v.s;
00088   while (t < top) *t++ = *u++;
00089 }
00090 
00091 intVec::intVec(int l, int  fill_value)
00092 {
00093   s = new int [len = l];
00094   int* top = &(s[len]);
00095   int* t = s;
00096   while (t < top) *t++ = fill_value;
00097 }
00098 
00099 
00100 intVec& intVec::operator = (const intVec& v)
00101 {
00102   if (this != &v)
00103   {
00104     delete [] s;
00105     s = new int [len = v.len];
00106     int* top = &(s[len]);
00107     int* t = s;
00108     const int* u = v.s;
00109     while (t < top) *t++ = *u++;
00110   }
00111   return *this;
00112 }
00113 
00114 void intVec::apply(intProcedure f)
00115 {
00116   int* top = &(s[len]);
00117   int* t = s;
00118   while (t < top) (*f)(*t++);
00119 }
00120 
00121 // can't just realloc since there may be need for constructors/destructors
00122 void intVec::resize(int newl)
00123 {
00124   int* news = new int [newl];
00125   int* p = news;
00126   int minl = (len < newl)? len : newl;
00127   int* top = &(s[minl]);
00128   int* t = s;
00129   while (t < top) *p++ = *t++;
00130   delete [] s;
00131   s = news;
00132   len = newl;
00133 }
00134 
00135 intVec concat(intVec & a, intVec & b)
00136 {
00137   int newl = a.len + b.len;
00138   int* news = new int [newl];
00139   int* p = news;
00140   int* top = &(a.s[a.len]);
00141   int* t = a.s;
00142   while (t < top) *p++ = *t++;
00143   top = &(b.s[b.len]);
00144   t = b.s;
00145   while (t < top) *p++ = *t++;
00146   return intVec(newl, news);
00147 }
00148 
00149 
00150 intVec combine(intCombiner f, intVec& a, intVec& b)
00151 {
00152   int newl = (a.len < b.len)? a.len : b.len;
00153   int* news = new int [newl];
00154   int* p = news;
00155   int* top = &(a.s[newl]);
00156   int* t = a.s;
00157   int* u = b.s;
00158   while (t < top) *p++ = (*f)(*t++, *u++);
00159   return intVec(newl, news);
00160 }
00161 
00162 int intVec::reduce(intCombiner f, int  base)
00163 {
00164   int r = base;
00165   int* top = &(s[len]);
00166   int* t = s;
00167   while (t < top) r = (*f)(r, *t++);
00168   return r;
00169 }
00170 
00171 intVec reverse(intVec& a)
00172 {
00173   int* news = new int [a.len];
00174   if (a.len != 0)
00175   {
00176     int* lo = news;
00177     int* hi = &(news[a.len - 1]);
00178     while (lo < hi)
00179     {
00180       int tmp = *lo;
00181       *lo++ = *hi;
00182       *hi-- = tmp;
00183     }
00184   }
00185   return intVec(a.len, news);
00186 }
00187 
00188 void intVec::reverse()
00189 {
00190   if (len != 0)
00191   {
00192     int* lo = s;
00193     int* hi = &(s[len - 1]);
00194     while (lo < hi)
00195     {
00196       int tmp = *lo;
00197       *lo++ = *hi;
00198       *hi-- = tmp;
00199     }
00200   }
00201 }
00202 
00203 int intVec::index(int  targ)
00204 {
00205   for (int i = 0; i < len; ++i) if (intEQ(targ, s[i])) return i;
00206   return -1;
00207 }
00208 
00209 intVec map(intMapper f, intVec& a)
00210 {
00211   int* news = new int [a.len];
00212   int* p = news;
00213   int* top = &(a.s[a.len]);
00214   int* t = a.s;
00215   while(t < top) *p++ = (*f)(*t++);
00216   return intVec(a.len, news);
00217 }
00218 
00219 int operator == (intVec& a, intVec& b)
00220 {
00221   if (a.len != b.len)
00222     return 0;
00223   int* top = &(a.s[a.len]);
00224   int* t = a.s;
00225   int* u = b.s;
00226   while (t < top) if (!(intEQ(*t++, *u++))) return 0;
00227   return 1;
00228 }
00229 
00230 void intVec::fill(int  val, int from, int n)
00231 {
00232   int to;
00233   if (n < 0)
00234     to = len - 1;
00235   else
00236     to = from + n - 1;
00237   if ((unsigned)from > (unsigned)to)
00238     range_error();
00239   int* t = &(s[from]);
00240   int* top = &(s[to]);
00241   while (t <= top) *t++ = val;
00242 }
00243 
00244 intVec intVec::at(int from, int n)
00245 {
00246   int to;
00247   if (n < 0)
00248   {
00249     n = len - from;
00250     to = len - 1;
00251   }
00252   else
00253     to = from + n - 1;
00254   if ((unsigned)from > (unsigned)to)
00255     range_error();
00256   int* news = new int [n];
00257   int* p = news;
00258   int* t = &(s[from]);
00259   int* top = &(s[to]);
00260   while (t <= top) *p++ = *t++;
00261   return intVec(n, news);
00262 }
00263 
00264 intVec merge(intVec & a, intVec & b, intComparator f)
00265 {
00266   int newl = a.len + b.len;
00267   int* news = new int [newl];
00268   int* p = news;
00269   int* topa = &(a.s[a.len]);
00270   int* as = a.s;
00271   int* topb = &(b.s[b.len]);
00272   int* bs = b.s;
00273 
00274   for (;;)
00275   {
00276     if (as >= topa)
00277     {
00278       while (bs < topb) *p++ = *bs++;
00279       break;
00280     }
00281     else if (bs >= topb)
00282     {
00283       while (as < topa) *p++ = *as++;
00284       break;
00285     }
00286     else if ((*f)(*as, *bs) <= 0)
00287       *p++ = *as++;
00288     else
00289       *p++ = *bs++;
00290   }
00291   return intVec(newl, news);
00292 }
00293 
00294 static int gsort(int*, int, intComparator);
00295  
00296 void intVec::sort (intComparator compar)
00297 {
00298   gsort(s, len, compar);
00299 }
00300 
00301 
00302 // An adaptation of Schmidt's new quicksort
00303 
00304 static inline void SWAP(int* A, int* B)
00305 {
00306   int tmp = *A; *A = *B; *B = tmp;
00307 }
00308 
00309 /* This should be replaced by a standard ANSI macro. */
00310 #define BYTES_PER_WORD 8
00311 #define BYTES_PER_LONG 4
00312 
00313 /* The next 4 #defines implement a very fast in-line stack abstraction. */
00314 
00315 #define STACK_SIZE (BYTES_PER_WORD * BYTES_PER_LONG)
00316 #define PUSH(LOW,HIGH) do {top->lo = LOW;top++->hi = HIGH;} while (0)
00317 #define POP(LOW,HIGH)  do {LOW = (--top)->lo;HIGH = top->hi;} while (0)
00318 #define STACK_NOT_EMPTY (stack < top)                
00319 
00320 /* Discontinue quicksort algorithm when partition gets below this size.
00321    This particular magic number was chosen to work best on a Sun 4/260. */
00322 #define MAX_THRESH 4
00323 
00324 
00325 /* Order size using quicksort.  This implementation incorporates
00326    four optimizations discussed in Sedgewick:
00327    
00328    1. Non-recursive, using an explicit stack of pointer that
00329       store the next array partition to sort.  To save time, this
00330       maximum amount of space required to store an array of
00331       MAX_INT is allocated on the stack.  Assuming a 32-bit integer,
00332       this needs only 32 * sizeof (stack_node) == 136 bits.  Pretty
00333       cheap, actually.
00334 
00335    2. Chose the pivot element using a median-of-three decision tree.
00336       This reduces the probability of selecting a bad pivot value and 
00337       eliminates certain extraneous comparisons.
00338 
00339    3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
00340       insertion sort to order the MAX_THRESH items within each partition.  
00341       This is a big win, since insertion sort is faster for small, mostly
00342       sorted array segements.
00343    
00344    4. The larger of the two sub-partitions is always pushed onto the
00345       stack first, with the algorithm then concentrating on the
00346       smaller partition.  This *guarantees* no more than log (n)
00347       stack size is needed! */
00348       
00349 static int gsort (int *base_ptr, int total_elems, intComparator cmp)
00350 {
00351 /* Stack node declarations used to store unfulfilled partition obligations. */
00352   struct stack_node {  int *lo;  int *hi; };
00353   int   pivot_buffer;
00354   int   max_thresh   = MAX_THRESH;
00355 
00356   if (total_elems > MAX_THRESH)
00357     {
00358       int       *lo = base_ptr;
00359       int       *hi = lo + (total_elems - 1);
00360       int       *left_ptr;
00361       int       *right_ptr;
00362       stack_node stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
00363       stack_node *top = stack + 1;
00364 
00365       while (STACK_NOT_EMPTY)
00366         {
00367           {
00368             int *pivot = &pivot_buffer;
00369             {
00370               /* Select median value from among LO, MID, and HI. Rearrange
00371                  LO and HI so the three values are sorted. This lowers the 
00372                  probability of picking a pathological pivot value and 
00373                  skips a comparison for both the LEFT_PTR and RIGHT_PTR. */
00374 
00375               int *mid = lo + ((hi - lo) >> 1);
00376 
00377               if ((*cmp) (*mid, *lo) < 0)
00378                 SWAP (mid, lo);
00379               if ((*cmp) (*hi, *mid) < 0)
00380               {
00381                 SWAP (mid, hi);
00382                 if ((*cmp) (*mid, *lo) < 0)
00383                   SWAP (mid, lo);
00384               }
00385               *pivot = *mid;
00386               pivot = &pivot_buffer;
00387             }
00388             left_ptr  = lo + 1;
00389             right_ptr = hi - 1; 
00390 
00391             /* Here's the famous ``collapse the walls'' section of quicksort.  
00392                Gotta like those tight inner loops!  They are the main reason 
00393                that this algorithm runs much faster than others. */
00394             do 
00395               {
00396                 while ((*cmp) (*left_ptr, *pivot) < 0)
00397                   left_ptr += 1;
00398 
00399                 while ((*cmp) (*pivot, *right_ptr) < 0)
00400                   right_ptr -= 1;
00401 
00402                 if (left_ptr < right_ptr) 
00403                   {
00404                     SWAP (left_ptr, right_ptr);
00405                     left_ptr += 1;
00406                     right_ptr -= 1;
00407                   }
00408                 else if (left_ptr == right_ptr) 
00409                   {
00410                     left_ptr += 1;
00411                     right_ptr -= 1;
00412                     break;
00413                   }
00414               } 
00415             while (left_ptr <= right_ptr);
00416 
00417           }
00418 
00419           /* Set up pointers for next iteration.  First determine whether
00420              left and right partitions are below the threshold size. If so, 
00421              ignore one or both.  Otherwise, push the larger partition's
00422              bounds on the stack and continue sorting the smaller one. */
00423 
00424           if ((right_ptr - lo) <= max_thresh)
00425             {
00426               if ((hi - left_ptr) <= max_thresh) /* Ignore both small partitions. */
00427                 POP (lo, hi); 
00428               else              /* Ignore small left partition. */  
00429                 lo = left_ptr;
00430             }
00431           else if ((hi - left_ptr) <= max_thresh) /* Ignore small right partition. */
00432             hi = right_ptr;
00433           else if ((right_ptr - lo) > (hi - left_ptr)) /* Push larger left partition indices. */
00434             {                   
00435               PUSH (lo, right_ptr);
00436               lo = left_ptr;
00437             }
00438           else                  /* Push larger right partition indices. */
00439             {                   
00440               PUSH (left_ptr, hi);
00441               hi = right_ptr;
00442             }
00443         }
00444     }
00445 
00446   /* Once the BASE_PTR array is partially sorted by quicksort the rest
00447      is completely sorted using insertion sort, since this is efficient 
00448      for partitions below MAX_THRESH size. BASE_PTR points to the beginning 
00449      of the array to sort, and END_PTR points at the very last element in
00450      the array (*not* one beyond it!). */
00451 
00452 
00453   {
00454     int *end_ptr = base_ptr + 1 * (total_elems - 1);
00455     int *run_ptr;
00456     int *tmp_ptr = base_ptr;
00457     int *thresh  = (end_ptr < (base_ptr + max_thresh))? 
00458       end_ptr : (base_ptr + max_thresh);
00459 
00460     /* Find smallest element in first threshold and place it at the
00461        array's beginning.  This is the smallest array element,
00462        and the operation speeds up insertion sort's inner loop. */
00463 
00464     for (run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr += 1)
00465       if ((*cmp) (*run_ptr, *tmp_ptr) < 0)
00466         tmp_ptr = run_ptr;
00467 
00468     if (tmp_ptr != base_ptr)
00469       SWAP (tmp_ptr, base_ptr);
00470 
00471     /* Insertion sort, running from left-hand-side up to `right-hand-side.' 
00472        Pretty much straight out of the original GNU qsort routine. */
00473 
00474     for (run_ptr = base_ptr + 1; (tmp_ptr = run_ptr += 1) <= end_ptr; )
00475       {
00476 
00477         while ((*cmp) (*run_ptr, *(tmp_ptr -= 1)) < 0)
00478           ;
00479 
00480         if ((tmp_ptr += 1) != run_ptr)
00481           {
00482             int *trav;
00483 
00484             for (trav = run_ptr + 1; --trav >= run_ptr;)
00485               {
00486                 int c = *trav;
00487                 int *hi, *lo;
00488 
00489                 for (hi = lo = trav; (lo -= 1) >= tmp_ptr; hi = lo)
00490                   *hi = *lo;
00491                 *hi = c;
00492               }
00493           }
00494 
00495       }
00496   }
00497   return 1;
00498 }

Generated on Tue Mar 6 16:47:46 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6