home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Internet 2000 May / MICD_2000_05.iso / CBuilder5 / INSTALL / DATA1.CAB / Program_Built_Files / Include / Vcl / sysdyn.h < prev    next >
C/C++ Source or Header  |  2000-02-01  |  10KB  |  386 lines

  1. // SYSDYN.H: Pascal Dynamic array type
  2. //
  3. // $Revision:   1.22  $
  4. // $Date:   14 Jul 1999 12:32:26  $
  5. //
  6. // Copyright (c) 1997, 1999 Borland International
  7.  
  8. #if !defined(SYSDYN_H)      // dynamic array
  9. #define SYSDYN_H
  10.  
  11. #if !defined(SystemHPP)
  12. #error Do not include this file directly.  Include 'system.hpp'.
  13. #endif
  14.  
  15. #if !defined(SYSMAC_H)
  16. #include <sysmac.h>
  17. #endif
  18.  
  19. #if !defined(SystemHPP)
  20. #include <system.hpp>
  21. #endif
  22.  
  23. #include <stdlib.h>        // malloc, free
  24.  
  25. namespace System
  26. {
  27.   class DynArrayException
  28.   {};
  29.  
  30.   /////////////////////////////////////////////////////////////////////////////
  31.   // Exception thrown when 'out-of-range' of an DynamicArray
  32.   /////////////////////////////////////////////////////////////////////////////
  33.   class DynArrayOutOfRange : public DynArrayException
  34.   {
  35.   public:
  36.     DynArrayOutOfRange(int index, int count) : m_Index(index),
  37.                                                m_Count(count)
  38.     {}
  39.  
  40.     int m_Index;
  41.     int m_Count;
  42.   };
  43.  
  44.   /////////////////////////////////////////////////////////////////////////////
  45.   // Exceptions thrown when 'accessing a Null' DynamicArray
  46.   /////////////////////////////////////////////////////////////////////////////
  47.   class DynArrayNullData : public DynArrayException
  48.   {};
  49.  
  50.  
  51.   template <class T> class RTL_DELPHIRETURN DynamicArray;
  52.  
  53.   /////////////////////////////////////////////////////////////////////////////
  54.   // NOTE: The following two template functions are used to determine the number of
  55.   //       dimensions in a dynamic array. This approach relies on the fact that the
  56.   //       resolution mechanism will use the first version of 'GetDimensions' as long
  57.   //       as we're dealing with a DynamicArray Of DynamicArray.
  58.   /////////////////////////////////////////////////////////////////////////////
  59.   template <class T> inline int
  60.   GetDimensions(const DynamicArray<T>& t) { return t.DimCount();}
  61.  
  62.   template <class T> inline int
  63.   GetDimensions(const T&) { return 0;}
  64.  
  65.  
  66.  
  67.   /////////////////////////////////////////////////////////////////////////////
  68.   // DynamicArray
  69.   // ============
  70.   // Template providing Delphi style Dynamic Array support in C++
  71.   /////////////////////////////////////////////////////////////////////////////
  72.   template<class T> class RTL_DELPHIRETURN DynamicArray
  73.   {
  74.   public:
  75.     DynamicArray();
  76.    ~DynamicArray();
  77.  
  78.     // Construct from another DynArray
  79.     DynamicArray(const DynamicArray<T>& src);
  80.  
  81.     // Assign data from another DynArray
  82.     DynamicArray& operator=(const DynamicArray<T>& src);
  83.  
  84.     // Subscript operator to access data
  85.     T& operator[](int index);
  86.     T  operator[](int index) const;
  87.  
  88.     // Comparison (NOTE: only pointer is compared)
  89.     bool operator == (const DynamicArray<T> &other) const;
  90.  
  91.     // Make copy of data (non-refcounted)
  92.     DynamicArray<T> Copy() const;
  93.     void            Copy(DynamicArray<T> &dst) const;
  94.     DynamicArray<T> CopyRange(int startIndex, int count) const;
  95.     void            CopyRange(DynamicArray<T> &dst, int startIndex, int count) const;
  96.  
  97.     // High and low bounds of DynArray
  98.     int             get_high() const;
  99.     int             get_low() const;
  100.  
  101.     // Set/get length of DynArray
  102.     int             get_length() const;
  103.     void            set_length(int l);
  104.  
  105. #if defined(DEBUG)
  106.     int             get_refCount() const;
  107. #endif
  108.  
  109.     // Properties
  110.   __property    int Length = {read=get_length, write=set_length};
  111.   __property    int High   = {read=get_high};
  112.   __property    int Low    = {read=get_low};
  113.  
  114. #if defined(DEBUG)
  115.   __property    int RefCount = {read=get_refCount};
  116. #endif
  117.  
  118.     // Returns number of dimensions of dynamic array
  119.     // NOTE: Used with 'GetDimensions' template functions above.
  120.     //       If T happens to be another DynamicArray, the compiler
  121.     //       resolves the call to the first version of GetDimensions.
  122.     //       Otherwise, it defaults to the second version.
  123.     //
  124.     static  int     DimCount()
  125.     {
  126.       return 1 + GetDimensions(*((T*)(0)));
  127.     }
  128.  
  129.   protected:
  130.     void            IncRefCount();
  131.     void            DecRefCount();
  132.     static T*       AllocData(int count);
  133.     void            SetData(T* t);
  134.     void            FreeData();
  135.  
  136.   private:
  137.       T*              Data;
  138.   };
  139.  
  140.   // Operator used in placement syntax
  141.   //
  142.   inline void* operator new(size_t size, char *p)
  143.   {
  144.     return p;
  145.   }
  146.  
  147.  
  148.   template <class T>
  149.   DynamicArray<T>::DynamicArray() : Data(0)
  150.   {}
  151.  
  152.   template <class T>
  153.   DynamicArray<T>::~DynamicArray()
  154.   {
  155.     DecRefCount();
  156.     Data = 0;
  157.   }
  158.  
  159.   template <class T>
  160.   DynamicArray<T>::DynamicArray(const DynamicArray<T>& src) : Data(src.Data)
  161.   {
  162.     IncRefCount();
  163.   }
  164.  
  165.   template <class T> DynamicArray<T>&
  166.   DynamicArray<T>::operator =(const DynamicArray<T>& src)
  167.   {
  168.     if (&src != this)
  169.     {
  170.       DecRefCount();
  171.       Data = src.Data;
  172.       IncRefCount();
  173.     }
  174.     return *this;
  175.   }
  176.  
  177.   template <class T> T&
  178.   DynamicArray<T>::operator[](int index)
  179.   {
  180.     if (index < 0 || index >= this->Length)
  181.       throw DynArrayOutOfRange(index, this->Length);
  182.     if (!Data)
  183.       throw DynArrayNullData();
  184.  
  185.     return *(Data + index);
  186.   }
  187.  
  188.   template <class T> T
  189.   DynamicArray<T>::operator[](int index) const
  190.   {
  191.     if (index < 0 || index >= this->Length)
  192.       throw DynArrayOutOfRange(index, this->Length);
  193.     if (!Data)
  194.       throw DynArrayNullData();
  195.  
  196.     return *(Data + index);
  197.   }
  198.  
  199.   template <class T> bool
  200.   DynamicArray<T>::operator == (const DynamicArray<T> &other) const
  201.   {
  202.     return Data == other.Data;
  203.   }
  204.  
  205.   template <class T> DynamicArray<T>
  206.   DynamicArray<T>::Copy() const
  207.   {
  208.     DynamicArray<T> cpy;
  209.     Copy(cpy);
  210.     return cpy;
  211.   }
  212.  
  213.   template <class T> void
  214.   DynamicArray<T>::Copy(DynamicArray<T>& dst) const
  215.   {
  216.     // Update length of destination if necessary
  217.     int l = (*this).Length;
  218.     if (dst.Length != l)
  219.       dst.Length = l;
  220.  
  221.     // Copy data over
  222.     for (int i=0; i<l; i++)
  223.       dst[i] = (*this)[i];
  224.   }
  225.  
  226.   template <class T> DynamicArray<T>
  227.   DynamicArray<T>::CopyRange(int startIndex, int  count) const
  228.   {
  229.     DynamicArray<T> cpy;
  230.     CopyRange(cpy, startIndex, count);
  231.     return cpy;
  232.   }
  233.  
  234.   template <class T> void
  235.   DynamicArray<T>::CopyRange(DynamicArray<T>& dst, int startIndex, int count) const
  236.   {
  237.     // Resize destination if necessary
  238.     // (Could optimize to only resize if too small!! However, Delphi always resizes)
  239.     if (dst.Length != count)
  240.       dst.Length = count;
  241.     // Copy data over
  242.     for (int i=0; i<count; i++)
  243.       dst[i] = (*this)[startIndex+i];
  244.   }
  245.  
  246.   template <class T> int
  247.   DynamicArray<T>::get_high() const
  248.   {
  249.     return Data ? get_length()-1 : 0;
  250.   }
  251.  
  252.   template <class T> int
  253.   DynamicArray<T>::get_low() const
  254.   {
  255.     return 0;
  256.   }
  257.  
  258.   template <class T> int
  259.   DynamicArray<T>::get_length() const
  260.   {
  261.     int *p_i = (int*)Data;
  262.     return Data ? *(p_i-1) : 0;
  263.   }
  264.  
  265.   template <class T> void
  266.   DynamicArray<T>::set_length(int l)
  267.   {
  268.     // Allocate space for new length
  269.     T* p = AllocData(l);
  270.  
  271.     // Copy data other if necessary
  272.     if (p)
  273.     {
  274.       // Compute length of data to be copied
  275.       int copyLen = (*this).Length;
  276.       if (l < copyLen)
  277.         copyLen = l;
  278.  
  279.       // Copy data
  280.       while (copyLen-- > 0)
  281.         p[copyLen] = (*this)[copyLen];
  282.     }
  283.  
  284.     // Assign new data...
  285.     SetData(p);
  286.   }
  287.  
  288. #if defined(DEBUG)
  289.   template <class T> int
  290.   DynamicArray<T>::get_refCount() const
  291.   {
  292.     int* p_i = (int*)Data;
  293.     return Data ? *(p_i-2) : 0;
  294.   }
  295. #endif;
  296.  
  297.   template <class T> void
  298.   DynamicArray<T>::IncRefCount()
  299.   {
  300.     if (Data)
  301.     {
  302.       int* p_i = (int*)Data;
  303.       int &refcount = *(p_i-2);
  304.       refcount++;
  305.     }
  306.   }
  307.  
  308.   template <class T> void
  309.   DynamicArray<T>::DecRefCount()
  310.   {
  311.     if (Data)
  312.     {
  313.       int* p_i = (int*)Data;
  314.       int &refcount = *(p_i-2);
  315.       if (--refcount == 0)
  316.         FreeData();
  317.     }
  318.   }
  319.  
  320.   template <class T> T*
  321.   DynamicArray<T>::AllocData(int count)
  322.   {
  323.     // NOTE: Length of zero results in a null data pointer
  324.     if (count == 0)
  325.       return 0;
  326.  
  327.     // Allocate memory: Array members + 2 integers (refcount and length)
  328.     //  NOTE: Don't use new to be compatible with Pascal memory manager
  329.     /* int *pi = (int*)new char[sizeof(T)*count + 2*sizeof(int)]; */
  330.     int *pi = (int*)malloc(sizeof(T)*count + 2*sizeof(int));
  331.  
  332.     // Initialize refcount + length
  333.     *pi++ = 1;         // RefCount initialized to 1
  334.     *pi++ = count;     // Set length of array
  335.  
  336.     T *pt = (T*)pi;
  337.     char *pc = (char*)pi;
  338.     T *p  = (T*)pc;
  339.  
  340.     // Invoke constructor for each member of array
  341.     while (count-- > 0)
  342.     {
  343.       new  (pc) T;
  344.       pc = (char*)(++p);
  345.     }
  346.  
  347.     // Return pointer
  348.     return pt;
  349.   }
  350.  
  351.   template <class T> void
  352.   DynamicArray<T>::SetData(T* t)
  353.   {
  354.     if (Data != t)
  355.     {
  356.       DecRefCount();
  357.       Data = t;
  358.     }
  359.   }
  360.  
  361.   template <class T> void
  362.   DynamicArray<T>::FreeData()
  363.   {
  364.     if (Data)
  365.     {
  366.       // Invoke destructor on each element
  367.       T*  p = Data;
  368.       int l = (*this).Length;
  369.  
  370.       for (; l-- > 0; p++)
  371.         p->~T();
  372.  
  373.       // Free chunk of memory
  374.       // NOTE: Don't use delete []p_i to be compatible with Delphi's memory manager
  375.       int* p_i = (int*)Data;
  376.       p_i -= 2;
  377.       free(p_i);
  378.       Data = 0;
  379.     }
  380.   }
  381.  
  382. } // namespace System
  383.  
  384.  
  385. #endif
  386.