home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 20 / AACD20.BIN / AACD / Programming / Jikes / Source / src / tuple.h < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-24  |  11.8 KB  |  449 lines

  1. // $Id: tuple.h,v 1.14 2001/02/01 10:24:07 mdejong Exp $
  2. //
  3. // This software is subject to the terms of the IBM Jikes Compiler
  4. // License Agreement available at the following URL:
  5. // http://www.ibm.com/research/jikes.
  6. // Copyright (C) 1996, 1998, International Business Machines Corporation
  7. // and others.  All Rights Reserved.
  8. // You must accept the terms of that agreement to use this software.
  9. //
  10. #ifndef TUPLE_INCLUDED
  11. #define TUPLE_INCLUDED
  12.  
  13. #include "jikesapi.h"
  14.  
  15. #ifdef    HAVE_JIKES_NAMESPACE
  16. namespace Jikes {    // Open namespace Jikes block
  17. #endif
  18.  
  19. class OutputBuffer;
  20.  
  21. //
  22. // This Tuple template class can be used to construct a dynamic
  23. // array of arbitrary objects. The space for the array is allocated in
  24. // blocks of size 2**LOG_BLKSIZE. In declaring a tuple the user
  25. // may specify an estimate of how many elements he expects.
  26. // Based on that estimate, suitable value will be calsulated log_blksize
  27. // and base_increment. If these estimates are off, more space will be
  28. // allocated.
  29. //
  30. template <class T>
  31. class Tuple
  32. {
  33. protected:
  34.  
  35.     friend class OutputBuffer;
  36.  
  37.     enum { DEFAULT_LOG_BLKSIZE = 3, DEFAULT_BASE_INCREMENT = 4 };
  38.  
  39.     T **base;
  40.     int base_size,
  41.         top,
  42.         size;
  43.  
  44.     int log_blksize,
  45.         base_increment;
  46.  
  47.     inline int Blksize() { return (1 << log_blksize); }
  48.  
  49.     //
  50.     // Allocate another block of storage for the dynamic array.
  51.     //
  52.     inline void AllocateMoreSpace()
  53.     {
  54.         //
  55.         // The variable size always indicates the maximum number of
  56.         // elements that has been allocated for the array.
  57.         // Initially, it is set to 0 to indicate that the array is empty.
  58.         // The pool of available elements is divided into segments of size
  59.         // 2**log_blksize each. Each segment is pointed to by a slot in
  60.         // the array base.
  61.         //
  62.         // By dividing size by the size of the segment we obtain the
  63.         // index for the next segment in base. If base is full, it is
  64.         // reallocated.
  65.         //
  66.         //
  67.         int k = size >> log_blksize; // which segment?
  68.  
  69.         //
  70.         // If the base is overflowed, reallocate it and initialize the new elements to NULL.
  71.         //
  72.         if (k == base_size)
  73.         {
  74.             int old_base_size = base_size;
  75.             T **old_base = base;
  76.  
  77.             base_size += base_increment;
  78.             base = new T*[base_size];
  79.  
  80.             if (old_base != NULL)
  81.             {
  82.                 memmove(base, old_base, old_base_size * sizeof(T *));
  83.                 delete [] old_base;
  84.             }
  85.             memset(&base[old_base_size], 0, (base_size - old_base_size) * sizeof(T *));
  86.         }
  87.  
  88.         //
  89.         // We allocate a new segment and place its adjusted address in
  90.         // base[k]. The adjustment allows us to index the segment directly,
  91.         // instead of having to perform a subtraction for each reference.
  92.         // See operator[] below.
  93.         //
  94.         base[k] = new T[Blksize()];
  95.         base[k] -= size;
  96.  
  97.         //
  98.         // Finally, we update SIZE.
  99.         //
  100.         size += Blksize();
  101.  
  102.         return;
  103.     }
  104.  
  105. public:
  106.  
  107.     //
  108.     // This function is invoked with an integer argument n. It ensures
  109.     // that enough space is allocated for n elements in the dynamic array.
  110.     // I.e., that the array will be indexable in the range  (0..n-1)
  111.     //
  112.     // Note that this function can be used as a garbage collector.  When
  113.     // invoked with no argument(or 0), it frees up all dynamic space that
  114.     // was allocated for the array.
  115.     //
  116.     inline void Resize(const int n = 0)
  117.     {
  118.         //
  119.         // If array did not previously contain enough space, allocate
  120.         // the necessary additional space. Otherwise, if the array had
  121.         // more blocks than are needed, release the extra blocks.
  122.         //
  123.         if (n > size)
  124.         {
  125.             do
  126.             {
  127.                 AllocateMoreSpace();
  128.             } while (n > size);
  129.         }
  130.         else if (n < size)
  131.         {
  132.             // slot is the index of the base element whose block
  133.             // will contain the (n-1)th element.
  134.             int slot = (n <= 0 ? -1 : (n - 1) >> log_blksize);
  135.  
  136.             for (int k = (size >> log_blksize) - 1; k > slot; k--)
  137.             {
  138.                 size -= Blksize();
  139.                 base[k] += size;
  140.                 delete [] base[k];
  141.                 base[k] = NULL;
  142.             }
  143.  
  144.             if (slot < 0)
  145.             {
  146.                 delete [] base;
  147.                 base = NULL;
  148.                 base_size = 0;
  149.             }
  150.         }
  151.  
  152.         top  = n;
  153.     }
  154.  
  155.     //
  156.     // This function is used to reset the size of a dynamic array without
  157.     // allocating or deallocting space. It may be invoked with an integer
  158.     // argument n which indicates the new size or with no argument which
  159.     // indicates that the size should be reset to 0.
  160.     //
  161.     inline void Reset(const int n = 0)
  162.     {
  163.         assert(n >= 0 && n <= size);
  164.  
  165.         top = n;
  166.     }
  167.  
  168.     //
  169.     // Return length of the dynamic array.
  170.     //
  171.     inline int Length() { return top; }
  172.  
  173.     //
  174.     // Return a reference to the ith element of the dynamic array.
  175.     //
  176.     // Note that no check is made here to ensure that 0 <= i < top.
  177.     // Such a check might be useful for debugging and a range exception
  178.     // should be thrown if it yields true.
  179.     //
  180.     inline T& operator[](const int i)
  181.     {
  182.         assert(i >= 0 && i < top);
  183.  
  184.         return base[i >> log_blksize][i];
  185.     }
  186.  
  187.     //
  188.     // Add an element to the dynamic array and return the top index.
  189.     //
  190.     inline int NextIndex()
  191.     {
  192.         int i = top++;
  193.         if (i == size)
  194.             AllocateMoreSpace();
  195.         return i;
  196.     }
  197.  
  198.     inline void Push(T elt) { this -> Next() = elt; }
  199.     // Not "return (*this)[--top]" because that may violate an invariant
  200.     // in operator[].
  201.     inline T Pop() { assert(top!=0); top--; return base[top >> log_blksize][top]; }
  202.     inline T Top() { assert(top!=0); return (*this)[top-1]; }
  203.  
  204.     //
  205.     // Add an element to the dynamic array and return a reference to
  206.     // that new element.
  207.     //
  208.     inline T& Next() { int i = NextIndex(); return base[i >> log_blksize][i]; }
  209.  
  210.     //
  211.     // Assignment of a dynamic array to another.
  212.     //
  213.     inline Tuple<T>& operator=(const Tuple<T>& rhs)
  214.     {
  215.         if (this != &rhs)
  216.         {
  217.             Resize(rhs.top);
  218.             for (int i = 0; i < rhs.top; i++)
  219.                 base[i >> log_blksize][i] = rhs.base[i >> log_blksize][i];
  220.         }
  221.  
  222.         return *this;
  223.     }
  224.  
  225.     //
  226.     // Constructor of a Tuple
  227.     //
  228.     Tuple(unsigned estimate = 0)
  229.     {
  230.         if (estimate == 0)
  231.         {
  232.             log_blksize = DEFAULT_LOG_BLKSIZE;
  233.             base_increment = DEFAULT_BASE_INCREMENT;
  234.         }
  235.         else
  236.         {
  237.             for (log_blksize = 1; (((unsigned) 1 << log_blksize) < estimate) && (log_blksize < 31); log_blksize++)
  238.                 ;
  239.             if (log_blksize <= DEFAULT_LOG_BLKSIZE)
  240.                 base_increment = 1;
  241.             else if (log_blksize < 13)
  242.             {
  243.                 base_increment = (unsigned) 1 << (log_blksize - 4);
  244.                 log_blksize = 4;
  245.             }
  246.             else
  247.             {
  248.                 base_increment = (unsigned) 1 << (log_blksize - 8);
  249.                 log_blksize = 8;
  250.             }
  251.             base_increment++; // add a little margin to avoid reallocating the base.
  252.         }
  253.  
  254.         base_size = 0;
  255.         size = 0;
  256.         top = 0;
  257.         base = NULL;
  258.     }
  259.  
  260.     //
  261.     // Constructor of a Tuple
  262.     //
  263.     Tuple(int log_blksize_, int base_increment_) : log_blksize(log_blksize_),
  264.                                                    base_increment(base_increment_)
  265.     {
  266.         base_size = 0;
  267.         size = 0;
  268.         top = 0;
  269.         base = NULL;
  270.     }
  271.  
  272.     //
  273.     // Initialization of a dynamic array.
  274.     //
  275.     Tuple(const Tuple<T>& rhs) : log_blksize(rhs.log_blksize),
  276.                                  base_increment(rhs.base_increment)
  277.     {
  278.         base_size = 0;
  279.         size = 0;
  280.         base = NULL;
  281.         *this = rhs;
  282.     }
  283.  
  284.     //
  285.     // Destructor of a dynamic array.
  286.     //
  287.     ~Tuple() { Resize(0); }
  288.  
  289.     // ********************************************************************************************** //
  290.  
  291.     //
  292.     // Return the total size of temporary space allocated.
  293.     //
  294.     inline size_t SpaceAllocated(void)
  295.     {
  296.         return ((base_size * sizeof(T **)) + (size * sizeof(T)));
  297.     }
  298.  
  299.     //
  300.     // Return the total size of temporary space used.
  301.     //
  302.     inline size_t SpaceUsed(void)
  303.     {
  304.         return (((size >> log_blksize) * sizeof(T **)) + (top * sizeof(T)));
  305.     }
  306. };
  307.  
  308.  
  309. //
  310. //
  311. //
  312. template <class T>
  313. class ConvertibleArray : public Tuple<T>
  314. {
  315. public:
  316.  
  317.     ConvertibleArray(int estimate = 0) : Tuple<T>(estimate),
  318.                                          array(NULL)
  319.     {}
  320.  
  321.     ConvertibleArray(int log_blksize, int base_increment) : Tuple<T>(log_blksize, base_increment),
  322.                                                             array(NULL)
  323.     {}
  324.  
  325.     ~ConvertibleArray() { delete [] array; }
  326.  
  327.     //
  328.     // This function converts a tuple into a regular array and destroys the
  329.     // original tuple.
  330.     //
  331.     inline T *&Array()
  332.     {
  333.         if ((! array) && Tuple<T>::top > 0)
  334.         {
  335.             array = new T[Tuple<T>::top];
  336.  
  337.             int i = 0,
  338.                 processed_size = 0,
  339.                 n = (Tuple<T>::top - 1) >> Tuple<T>::log_blksize; // the last non-empty slot!
  340.             while (i < n)
  341.             {
  342.                 memmove(&array[processed_size], Tuple<T>::base[i] + processed_size, Tuple<T>::Blksize() * sizeof(T));
  343.                 delete [] (Tuple<T>::base[i] + processed_size);
  344.                 i++;
  345.                 processed_size += Tuple<T>::Blksize();
  346.             }
  347.             memmove(&array[processed_size], Tuple<T>::base[n] + processed_size, (Tuple<T>::top - processed_size) * sizeof(T));
  348.             delete [] (Tuple<T>::base[n] + processed_size);
  349.             delete [] Tuple<T>::base;
  350.             Tuple<T>::base = NULL;
  351.             Tuple<T>::size = 0;
  352.         }
  353.  
  354.         return array;
  355.     }
  356.  
  357.     inline T& operator[](const int i)
  358.     {
  359.         assert(i >= 0 && i < Tuple<T>::top);
  360.  
  361.         return (array ? array[i] : Tuple<T>::base[i >> Tuple<T>::log_blksize][i]);
  362.     }
  363.  
  364.     inline void Resize(const int n = 0) { assert(false); }
  365.     inline void Reset(const int n = 0) { assert(false); }
  366.     inline T& Next()
  367.     {
  368.         assert(! array);
  369.  
  370.         int i = Tuple<T>::NextIndex();
  371.         return Tuple<T>::base[i >> Tuple<T>::log_blksize][i];
  372.     }
  373.     inline Tuple<T>& operator=(const Tuple<T>& rhs)
  374.     {
  375.         assert(false);
  376.         return *this;
  377.     }
  378.  
  379. private:
  380.  
  381.     T *array;
  382. };
  383.  
  384.  
  385. //
  386. //
  387. //
  388. class OutputBuffer
  389. {
  390. public:
  391.  
  392.     OutputBuffer(int log_blksize = 13, int base_increment = 128) : buffer(log_blksize, base_increment) {}
  393.  
  394.     inline void PutB1(u1 u) { buffer.Next() = u; }
  395.  
  396.     inline void PutB2(u2 u)
  397.     {
  398.         buffer.Next() = u >> 8;
  399.         buffer.Next() = u & 0xff;
  400.     }
  401.  
  402.     inline void PutB4(u4 u)
  403.     {
  404.         buffer.Next() = u >> 24;
  405.         buffer.Next() = (u >> 16) & 0xff;
  406.         buffer.Next() = (u >> 8)  & 0xff;
  407.         buffer.Next() = u & 0xff;
  408.     }
  409.  
  410.     inline void put_n(u1 *u, int n)
  411.     {
  412.         for (int i = 0; i < n; i++)
  413.             buffer.Next() = u[i];
  414.     }
  415.  
  416.     inline bool WriteToFile(char *file_name)
  417.     {
  418.         JikesAPI::FileWriter *file = JikesAPI::getInstance()->write(file_name,buffer.top);
  419.  
  420.         if (file == NULL) // NB if file was invalid it would already have been destroyed by write()
  421.             return false;
  422.  
  423.         size_t size  = 0;
  424.         int    n     = (buffer.top - 1) >> buffer.log_blksize; // the last non-empty slot!
  425.  
  426.         for (int i=0; i < n; i++)
  427.         {
  428.             file->write(buffer.base[i] + size, buffer.Blksize());
  429.             size += buffer.Blksize();
  430.         }
  431.         file->write(buffer.base[n] + size, (buffer.top - size));
  432.  
  433.         delete file;
  434.        
  435.         return true;
  436.     }
  437.  
  438. private:
  439.  
  440.     Tuple<u1> buffer;
  441. };
  442.  
  443. #ifdef    HAVE_JIKES_NAMESPACE
  444. }            // Close namespace Jikes block
  445. #endif
  446.  
  447. #endif /* #ifndef TUPLE_INCLUDED */
  448.  
  449.