LTP GCOV extension - code coverage report
Current view: directory - include/utilib - ArrayBase.h
Test: Acro
Date: 2008-10-21 Instrumented lines: 135
Code covered: 85.2 % Executed lines: 115

       1                 : /*  _________________________________________________________________________
       2                 :  *
       3                 :  *  UTILIB: A utility library for developing portable C++ codes.
       4                 :  *  Copyright (c) 2001, Sandia National Laboratories.
       5                 :  *  This software is distributed under the GNU Lesser General Public License.
       6                 :  *  For more information, see the README file in the top UTILIB directory.
       7                 :  *  _________________________________________________________________________
       8                 :  */
       9                 : 
      10                 : /**
      11                 :  * \file ArrayBase.h
      12                 :  *
      13                 :  * Defines the utilib::ArrayBase class
      14                 :  */
      15                 : 
      16                 : #ifndef utilib_ArrayBase_h
      17                 : #define utilib_ArrayBase_h
      18                 : 
      19                 : #include <utilib/std_headers.h>
      20                 : #include <utilib/_generic.h>
      21                 : #include <utilib/exception_mngr.h>
      22                 : 
      23                 : #include <utilib/Serialize.h>
      24                 : 
      25                 : namespace utilib {
      26                 : 
      27                 : /**
      28                 :  * \def ArraySanityChecking
      29                 :  *
      30                 :  * If the macro ArraySanityChecking=1 then some routine sanity checks will 
      31                 :  * be performed when accessing vectors.  Sanity checking generally degrades 
      32                 :  * performance.  The default is is to perform sanity checking.
      33                 :  *
      34                 :  * Note: Because inlines are typically put "in place" when the optimization flag
      35                 :  * -O is used, you can define some files with ArraySanityChecking=0 to 
      36                 :  * acheive better performance, while using the default debugging mode in the
      37                 :  * rest of the code.
      38                 :  */
      39                 : #if !defined(ArraySanityChecking)
      40                 : #define ArraySanityChecking    1
      41                 : #endif
      42                 : 
      43                 : template <class A, class P>
      44                 : class ArrayBase;
      45                 : 
      46                 : 
      47                 : /**
      48                 :  * This class implements sharable array objects.  This class implements
      49                 :  * features common to both regular arrays, such as BasicArray<T>,
      50                 :  * SimpleArray<T>, NumArray<T>, {Int,Real,Double}Vector, and CharString,
      51                 :  * and also bit-oriented arrays implemented via the BitArrayBase class.
      52                 :  * 
      53                 :  * It is essentially a replacement for the old ClassRef class, but 
      54                 :  * (for the time being, at least), only works for array-like objects
      55                 :  * that have a "length".
      56                 :  *
      57                 :  * The template argument "A" refers to what kind of memory objects 
      58                 :  * are actually allocated.  The template argument "P" refers to what
      59                 :  * kinds of pointers are stored to other objects sharing the same memory.
      60                 :  *
      61                 :  * This class differs from ClassRef in that sharing is implemented
      62                 :  * via an embedded linked list instead of a separate 
      63                 :  * ArrayRef/ClassRef object. That means there are two "extra" pointers 
      64                 :  * in the array object, but sharing is fairly simple, without any 
      65                 :  * overhead being imposed on the indexing [ ] operator.  The tradeoff
      66                 :  * is that resizing a shared array carries O(s) overhead, where s
      67                 :  * is the number of sharers.  Deletion is O(1), however.
      68                 :  *
      69                 :  */
      70                 : template <class A, class P>
      71                 : class ArrayBase
      72         2491781 : {
      73                 : public:
      74                 : 
      75                 :   /// Destructor
      76         2484655 :   virtual ~ArrayBase()
      77         2484655 :         { free(); }
      78                 : 
      79                 :   /// Returns true if this array shares data with another array.
      80               3 :   bool shared_mem() const
      81               3 :         { return true_pointer(prev_share) || next_share; }
      82                 : 
      83                 :   /// Resizes the array to the given, nonnegative, value.
      84                 :   /// If the second argument is non-zero (the default), the old contents
      85                 :   /// are copied, and if the new array is longer, the new elements
      86                 :   /// are set with the \b initialize method.
      87                 :   virtual void resize(const size_type newl,int set_new_contents=1);
      88                 : 
      89                 :   /// Returns true if size == 0 (for STL compatibility)
      90               0 :   bool empty() const
      91               0 :         { return Len == 0; }
      92                 : 
      93                 :   /// Returns the length of the array.
      94        14153277 :   size_type size() const
      95        14153277 :         { return Len; }
      96                 : 
      97                 :   /// This method controls the mapping of the size of the array
      98                 :   /// to the actual number of type "A" elements allocated.  The
      99                 :   /// default implementation is the identity mapping, which should
     100                 :   /// work for everything except BitArrays and CharStrings.
     101         2644683 :   virtual size_type alloc_size(size_type l) const
     102         2644683 :         { return l; }
     103                 : 
     104                 :   /// Same, but takes the size of the array as an effective default argument
     105               0 :   size_type allocation() const
     106               0 :         { return alloc_size(Len); }
     107                 : 
     108                 :   /// Returns the number of bytes used by the array
     109               0 :   size_type bytes_used() const
     110               0 :         { return allocation()*sizeof(A); }
     111                 : 
     112                 :   /// Returns the internal pointer to the array.
     113         2406866 :   A* data() const
     114         2406866 :         { return Data; }
     115                 : 
     116                 : #if 0
     117                 : #ifndef SWIG
     118                 : 
     119                 :   /// A coercion operator returning a pointer to the internal array
     120                 :   operator A* () const
     121                 :         { return Data; }
     122                 :   
     123                 : #endif
     124                 : #endif
     125                 : 
     126                 :   /// Returns the number of references to the internal array.
     127                 :   /// This method has to scan the entire share group and is 
     128                 :   /// now deprecated.
     129                 :   int nrefs() const;
     130                 : 
     131                 :   /// Disconnect from any prior data and copy the data from object \b array
     132                 :   ArrayBase<A,P>& operator=(const ArrayBase<A,P>& array);
     133                 : 
     134                 :   /// Set to share storage with \b array
     135                 :   ArrayBase<A,P>& operator&=(ArrayBase<A,P>& array);
     136                 : 
     137                 :   /// Method to explicitly set the Data pointer and length.
     138                 :   /// Applies to all members of the share group.
     139                 :   void set_data(const size_type len, 
     140                 :                 A* data,
     141                 :                 const EnumDataOwned o=DataNotOwned);
     142                 : 
     143                 :   /// Print debugging information to a stream
     144                 :   void debug_print(std::ostream& str,int max_elements=0);
     145                 : 
     146                 : protected:
     147                 : 
     148                 :   /// The pointer to this array's data.
     149                 :   A* Data;
     150                 : 
     151                 :   /// Pointer to the previous element of this share group.
     152                 :   /// If the first in a group, and the data is not owned, contains
     153                 :   /// the special pointer value special_not_owned_pointer().
     154                 :   P* prev_share;
     155                 : 
     156                 :   /// Pointer to the next element of this share group.
     157                 :   P* next_share;
     158                 : 
     159                 :   /// The length of the array in \a Data.  This is set up so that 
     160                 :   /// it is always equal to the user's perceived length of the array.
     161                 :   /// To get the actual number of type "A" elements allocated in \b Data,
     162                 :   /// apply the \b alloc_size method below.
     163                 :   size_type Len;
     164                 : 
     165                 :   /// This method copies from one data block to another.  The
     166                 :   /// default should suffice for regular arrays, but for BitArrays
     167                 :   /// and CharStrings it will need some tweaking.
     168                 :   virtual void copy_data(A*        target,
     169                 :                          size_type target_size,
     170                 :                          A*        source,
     171                 :                          size_type source_size);
     172                 :   
     173                 :   /// This method should be used by constructors of derived classes.
     174                 :   virtual void construct(const size_type     mylen, 
     175                 :                          A*                  d=0, 
     176                 :                          const EnumDataOwned o=DataNotOwned);
     177                 : 
     178                 :   /// Supply initial values to part of an array.  Default is 
     179                 :   /// a no-op, but for NumArrays this is overridden to set 0's.
     180                 :   virtual void initialize(A*              /*data*/, 
     181                 :                           const size_type /*start*/, 
     182          136508 :                           const size_type /*stop*/)
     183          136508 :         {}
     184                 : 
     185                 :   /// Unlink from storage.  Delete the associated memory if
     186                 :   /// nobody else is linked to it.
     187                 :   void free();
     188                 : 
     189                 :   /// Special bogus pointer to use to terminate the beginning of 
     190                 :   /// the list when the memory block is not owned by the array.
     191                 :   /// We assume that just as no data can live at address 0, it
     192                 :   /// can't live at address 1 either.
     193           61696 :   static P* special_not_owned_pointer()
     194           61696 :         { return (P*) 1; }
     195                 : 
     196                 :   /// Internal function for testing whether a pointer is valid.
     197                 :   /// Checks for both NULL and the special_not_owned_pointer().
     198         3738284 :   static int true_pointer(P* p)
     199         3738284 :         { return p && (p != special_not_owned_pointer()); }
     200                 : 
     201                 :   /// Generic method for dumping contents to a stream (debugging only)
     202                 :   /// Default is nothing.
     203               0 :   virtual void dump_data(std::ostream& /*str*/, unsigned int /*max_elements*/=0)
     204               0 :         {}
     205                 : 
     206                 :   /// The general serializer for all ArrayBase derivatives.
     207                 :   static int serializer( SerialObject::elementList_t& serial, 
     208                 :                          Any& data, bool serialize );
     209                 : 
     210                 : };
     211                 : 
     212                 : 
     213                 : ///
     214                 : /// METHOD DEFINITIONS
     215                 : ///
     216                 : 
     217                 : template <class A, class P>
     218                 : void ArrayBase<A,P>::construct(const size_type mylen, 
     219                 :                                A* d, 
     220         3020956 :                                const EnumDataOwned o)
     221                 : {
     222         3020956 :   Len = mylen;
     223                 : 
     224         3020956 :   if (d == NULL) 
     225                 :     {
     226         2401407 :       if (mylen > 0) 
     227                 :         {
     228          128407 :           size_type newlen = alloc_size(mylen);
     229          128407 :           Data = new A[newlen];
     230          128407 :           if (Data == 0)
     231               0 :              EXCEPTION_MNGR(runtime_error, "ArrayBase::construct - new A[" << alloc_size(mylen) << "] failed.");
     232          128407 :           initialize(Data,0,Len);
     233                 :         }
     234                 :       else
     235         2273000 :         Data = NULL;
     236                 :     }
     237                 :   else  // if d was supplied...
     238                 :     {
     239          619549 :       if (o == DataOwned) {
     240          607599 :         if (mylen > 0)  
     241                 :           {
     242          607578 :             size_type newlen = alloc_size(mylen);
     243          607578 :             Data = new A[newlen];
     244          607578 :             if (Data == 0)
     245               0 :                EXCEPTION_MNGR(runtime_error, "ArrayBase::construct - new A["
     246                 :                               << alloc_size(mylen) << "] failed.");
     247          607578 :             copy_data(Data,Len,d,Len);
     248                 :           }
     249                 :       }
     250                 :       else
     251           11950 :         Data = d;
     252                 :     }
     253                 : 
     254                 :   // Initialize the pointers to the rest of the share group, which is now
     255                 :   // empty.  Note that if the data is not owned, we use a special bogus value
     256                 :   // instead of NULL for the first pointer.
     257                 : 
     258         3032906 :   if ((o == DataNotOwned) && d)
     259           11950 :     prev_share = special_not_owned_pointer();
     260                 :   else
     261         3009006 :     prev_share = NULL;
     262                 : 
     263         3020956 :   next_share = NULL;
     264                 : 
     265                 : }
     266                 : 
     267                 : 
     268                 : template <class A, class P>
     269         2908938 : void ArrayBase<A,P>::free()
     270                 : {
     271                 :   // Unlink from previous member of share group, if any
     272                 : 
     273         2908938 :   if (true_pointer(prev_share))
     274           34868 :     prev_share->next_share = next_share;
     275                 : 
     276                 :   // Unlink from next member of share group, if any
     277                 : 
     278         2908938 :   if (next_share)
     279            2815 :     next_share->prev_share = prev_share;
     280                 : 
     281                 :   // If there were no other members and the data is owned, free memory.
     282                 : 
     283         2908938 :   if ((Data != NULL) && (prev_share == NULL) && (next_share == NULL))
     284         1189115 :     delete [] Data;
     285                 :   
     286                 : }
     287                 : 
     288                 : 
     289                 : template <class A, class P>
     290                 : void ArrayBase<A,P>::copy_data(A*        target,
     291                 :                                size_type target_size,
     292                 :                                A*        source,
     293         1036843 :                                size_type source_size)
     294                 : {
     295         1036843 :   size_type target_alloc = alloc_size(target_size);
     296         1036843 :   size_type source_alloc = alloc_size(source_size);
     297         2687856 :   for(size_type i=0; i < target_alloc && i < source_alloc; i++)
     298         2687856 :     *(target++) = *(source++);
     299                 : }
     300                 : 
     301                 : 
     302                 : 
     303                 : template <class A, class P>
     304          354389 : ArrayBase<A,P>& ArrayBase<A,P>::operator=(const ArrayBase<A,P>& array)
     305                 : {
     306          354389 :   if (this != &array) 
     307                 :     {
     308          354389 :       free();
     309          354389 :       construct(array.size(),array.data(),DataOwned);
     310                 :     }
     311          354389 :   return *this;
     312                 : }
     313                 : 
     314                 : 
     315                 : 
     316                 : template <class A, class P>
     317           37681 : ArrayBase<A,P>& ArrayBase<A,P>::operator&=(ArrayBase<A,P>& array)
     318                 : {
     319           37681 :   if (this == &array)
     320               1 :      return *this;
     321                 :     
     322           37680 :   if ((array.Data != Data) || (Data == NULL))
     323                 :     { 
     324           37680 :       free();
     325                 : 
     326           37680 :       Data = array.Data;
     327           37680 :       Len  = array.Len;
     328                 : 
     329           37680 :       prev_share = array.prev_share;
     330           37680 :       if (true_pointer(array.prev_share))
     331               4 :         array.prev_share->next_share = (P*) this;
     332           37680 :       array.prev_share = (P*) this;
     333           37680 :       next_share       = (P*) &array;
     334                 :     }
     335           37680 :   return *this;
     336                 : }
     337                 : 
     338                 : 
     339                 : 
     340                 : template <class A, class P>
     341         1029658 : void ArrayBase<A,P>::resize(const size_type newl,int set_new_contents)
     342                 : {
     343         1029658 :   if (newl == Len)
     344          240973 :     return;
     345                 :   
     346          788685 :   A* d = 0;
     347          788685 :   size_type new_alloc = alloc_size(newl);
     348                 :   
     349          788685 :   if (new_alloc == alloc_size(Len))
     350           68557 :     d = Data;
     351          720128 :   else if (newl > 0) 
     352                 :     {
     353          672763 :       d = new A[new_alloc];
     354          672763 :       if (d == 0)
     355               0 :          EXCEPTION_MNGR(runtime_error, "ArrayBase::resize - new T ["
     356                 :                         << new_alloc << "] failed.");
     357          672763 :       if (set_new_contents)
     358          672753 :          copy_data(d,newl,Data,Len);
     359                 :     }
     360                 : 
     361          788685 :   if (set_new_contents && (newl > Len))
     362          669550 :     initialize(d,Len,newl);
     363                 :   
     364          788685 :   set_data(newl,d,DataOwned);
     365                 : }
     366                 : 
     367                 : 
     368                 : template <class A, class P>
     369                 : void ArrayBase<A,P>::set_data(const size_type len, 
     370                 :                                          A* data, 
     371          788686 :                                          const EnumDataOwned o)
     372                 : {
     373          788686 :   if (len == 0) 
     374           47365 :     data = NULL;
     375                 : 
     376          788686 :   P* share = next_share;
     377                 : 
     378                 :   // Set data and size of all subsequent elements.
     379                 : 
     380          788692 :   for (; share; share = share->next_share)
     381                 :     {
     382               6 :       share->Data = data;
     383               6 :       share->Len  = len;
     384                 :     }
     385                 : 
     386                 :   // Set data and size for all elements except first in the chain.
     387                 :   // Leave share pointing to first in the chain.
     388                 : 
     389          791582 :   for (share = (P*) this; 
     390                 :        true_pointer(share->prev_share); 
     391                 :        share = share->prev_share)
     392                 :     {
     393            2896 :       share->Data = data;
     394            2896 :       share->Len  = len;
     395                 :     }
     396                 : 
     397                 :   // Free the old memory if necessary.
     398                 :   
     399          788686 :   if ((share->Data != NULL) && 
     400                 :       (share->Data != data) && 
     401                 :       (share->prev_share == NULL))
     402          213659 :     delete [] share->Data;
     403                 : 
     404                 :   // Set the length and data for the first chain member.
     405                 : 
     406          788686 :   share->Data = data;
     407          788686 :   share->Len  = len;
     408                 :   
     409                 :   // Set the ownership flag
     410                 : 
     411          788686 :   if (o == DataNotOwned)
     412               0 :     share->prev_share = special_not_owned_pointer();
     413                 :   else
     414          788686 :     share->prev_share = NULL;
     415                 : }
     416                 : 
     417                 : 
     418                 : template <class A, class P>
     419              59 : int ArrayBase<A,P>::nrefs() const
     420                 : {
     421              59 :   int n = 1;
     422                 :   P*  share;
     423              81 :   for (share = prev_share; true_pointer(share); share = share->prev_share)
     424              22 :     n++;
     425              73 :   for (share = next_share; share; share = share->next_share)
     426              14 :     n++;
     427              59 :   return n;
     428                 : }
     429                 :  
     430                 : 
     431                 : template <class A, class P>
     432               0 : void ArrayBase<A,P>::debug_print(std::ostream& str,int max_elements)
     433                 : {
     434               0 :   str << "this=" << this;
     435               0 :   str << " size=" << size() << " Data=" << (void*) Data;
     436               0 :   str << " prev_share=" << prev_share;
     437               0 :   if (prev_share == special_not_owned_pointer())
     438               0 :     str << "(not owned flag)";
     439               0 :   str << " next_share=" << next_share << std::endl;
     440                 :   //dump_data(str,max_elements);
     441                 : }
     442                 : 
     443                 : 
     444                 : /** Serialize an ArrayBase object.  Note: as no one will ever create a
     445                 :  *  ArrayBase object, we will not bother to register this with the
     446                 :  *  Serializer().
     447                 :  */
     448                 : template <class A, class P>
     449                 : int ArrayBase<A,P>::serializer( SerialObject::elementList_t& serial, 
     450              32 :                                 Any& data, bool serialize )
     451                 : {
     452                 :    ArrayBase<A,P>& tmp 
     453              32 :       = const_cast<ArrayBase<A,P>&>(data.expose<ArrayBase<A,P> >());
     454                 :    
     455              32 :    if ( ! serialize )
     456              16 :       tmp.resize(serial.size(), false);
     457                 :    
     458              32 :    A* it = tmp.Data;
     459              32 :    size_t index = tmp.Len;
     460              32 :    int ans = 0;
     461              88 :    for ( ; index > 0; ++it, --index )
     462              56 :       if ( 0 != (ans = serial_transform(serial, *it, serialize)) )
     463               0 :          return ans;
     464                 :       
     465              32 :    return 0;
     466                 : }
     467                 : 
     468                 : } // namespace utilib
     469                 : 
     470                 : #endif

Generated by: LTP GCOV extension version 1.4