Block.h

Go to the documentation of this file.
00001 //# Block.h: Simple templated array classes
00002 //# Copyright (C) 1993-1997,2000,2002,2005,2015
00003 //# Associated Universities, Inc. Washington DC, USA.
00004 //# National Astronomical Observatory of Japan
00005 //# 2-21-1, Osawa, Mitaka, Tokyo, 181-8588, Japan.
00006 //#
00007 //# This library is free software; you can redistribute it and/or modify it
00008 //# under the terms of the GNU Library General Public License as published by
00009 //# the Free Software Foundation; either version 2 of the License, or (at your
00010 //# option) any later version.
00011 //#
00012 //# This library is distributed in the hope that it will be useful, but WITHOUT
00013 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00015 //# License for more details.
00016 //#
00017 //# You should have received a copy of the GNU Library General Public License
00018 //# along with this library; if not, write to the Free Software Foundation,
00019 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00020 //#
00021 //# Correspondence concerning AIPS++ should be addressed as follows:
00022 //#        Internet email: aips2-request@nrao.edu.
00023 //#        Postal address: AIPS++ Project Office
00024 //#                        National Radio Astronomy Observatory
00025 //#                        520 Edgemont Road
00026 //#                        Charlottesville, VA 22903-2475 USA
00027 //#
00028 //# $Id$
00029 
00030 #ifndef CASA_BLOCK_H
00031 #define CASA_BLOCK_H
00032 
00033 #include <casacore/casa/aips.h>
00034 #include <casacore/casa/Utilities/Assert.h>
00035 #include <casacore/casa/Utilities/Copy.h>
00036 #include <casacore/casa/Utilities/DataType.h>
00037 #include <casacore/casa/Containers/Allocator.h>
00038 #include <cstddef>                  // for ptrdiff_t
00039 #include <algorithm> // for std:min/max
00040 #if __cplusplus < 201103L
00041 #include <cwchar>
00042 #else
00043 #include <type_traits>
00044 #endif
00045 
00046 //# For index checking
00047 #if defined(AIPS_ARRAY_INDEX_CHECK)
00048 #include <casacore/casa/Exceptions/Error.h>
00049 #endif
00050 
00051 namespace casacore { //# NAMESPACE CASACORE - BEGIN
00052 
00053 // <summary>simple 1-D array</summary>
00054 // <use visibility=export>
00055 //
00056 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00057 // </reviewed>
00058 //
00059 // <etymology>
00060 //     This should be viewed as a <em>block</em> of memory without sophisticated
00061 //     manipulation functions. Thus it is called <src>Block</src>.
00062 // </etymology>
00063 //
00064 // <synopsis>
00065 // <src>Block<T></src> is a simple templated 1-D array class. Indices are always
00066 // 0-based. For efficiency reasons, no index checking is done unless the
00067 // preprocessor symbol <src>AIPS_ARRAY_INDEX_CHECK</src> is defined. 
00068 // <src>Block<T></src>'s may be assigned to and constructed from other
00069 // <src>Block<T></src>'s.
00070 // As no reference counting is done this can be an expensive operation, however.
00071 //
00072 // The net effect of this class is meant to be unsurprising to users who think
00073 // of arrays as first class objects. The name "Block" is  intended to convey
00074 // the concept of a solid "chunk" of things without any intervening "fancy"
00075 // memory management, etc. This class was written to be
00076 // used in the implementations of more functional Vector, Matrix, etc. classes,
00077 // although it is expected <src>Block<T></src> will be useful on its own.
00078 //
00079 // The Block class should be efficient. You should normally use <src>Block</src>.
00080 //
00081 // <note role=warning> If you use the assignment operator on an element of this
00082 // class, you may leave dangling references to pointers released from
00083 // <src>storage()</src>.
00084 // Resizing the array will also have this effect if the underlying storage
00085 // is actually affected.
00086 // </note>
00087 //
00088 // If index checking is turned on, an out-of-bounds index will
00089 // generate an <src>indexError<uInt></src> exception.
00090 // </synopsis>
00091 //
00092 // <example> 
00093 // <srcblock>
00094 // Block<Int> a(100,0);  // 100 ints initialized to 0
00095 // Block<Int> b;         // 0-length Block
00096 // // ...
00097 // b = a;                // resize b and copy a into it
00098 // for (size_t i=0; i < a.nelements(); i++) {
00099 //     a[i] = i;    // Generate a sequence
00100 //                  // with Vectors, could simply say "indgen(myVector);"
00101 // }
00102 // b.set(-1);       // All positions in b have the value -1
00103 // b.resize(b.nelements()*2); // Make b twice as long, by default the old
00104 //                            // elements are copied over, although this can
00105 //                            // be defeated.
00106 // some_c_function(b.storage());  // Use a fn that takes an
00107 //                                // <src>Int *</src> pointer
00108 // </srcblock> 
00109 // </example>
00110 //
00111 class BlockTrace
00112 {
00113 public:
00114   // Set the trace size. The (de)allocation of Blocks with >= sz elements
00115   // will be traced using the MemoryTrace class.
00116   // A value 0 means no tracing.
00117   static void setTraceSize (size_t sz);
00118 protected:
00119   // Write alloc and free trace messages.
00120   static void doTraceAlloc (const void* addr, size_t nelem,
00121                             DataType type, size_t sz);
00122   static void doTraceFree (const void* addr, size_t nelem,
00123                            DataType type, size_t sz);
00124 protected:
00125   static size_t itsTraceSize;
00126 };
00127 
00128 template<typename T> class Block;
00129 
00130 #if __cplusplus < 201103L
00131 
00132 template<typename T>
00133 class Block_internal_IsFundamental {
00134   template<typename U> friend class Block;
00135   enum {value = 0};
00136 };
00137 
00138 template<typename T>
00139 class Block_internal_IsPointer {
00140   template<typename U> friend class Block;
00141   enum {value = 0};
00142 };
00143 
00144 #define CASA_TMP_939727(x) template<> class Block_internal_IsFundamental<x> { template<typename U> friend class Block; enum { value = 1 }; }
00145 CASA_TMP_939727(void);
00146 /*
00147 CASA_TMP_939727(char16_t);
00148 CASA_TMP_939727(char32_t);
00149 */
00150 CASA_TMP_939727(bool);
00151 CASA_TMP_939727(wchar_t);
00152 CASA_TMP_939727(signed char);
00153 CASA_TMP_939727(unsigned char);
00154 CASA_TMP_939727(float);
00155 CASA_TMP_939727(double);
00156 CASA_TMP_939727(long double);
00157 #define CASA_TMP_939727_int(x) CASA_TMP_939727(x); CASA_TMP_939727(unsigned x)
00158 CASA_TMP_939727_int(int);
00159 CASA_TMP_939727_int(long int);
00160 CASA_TMP_939727_int(long long int);
00161 #undef CASA_TMP_939727_int
00162 #undef CASA_TMP_939727
00163 
00164 template<typename T>
00165 class Block_internal_IsPointer<T *> {
00166   template<typename U> friend class Block;
00167   enum { value = 1 };
00168 };
00169 
00170 #else // __cplusplus < 201103L
00171 
00172 template<typename T>
00173 class Block_internal_IsFundamental {
00174   template<typename U> friend class Block;
00175   static constexpr int value = static_cast<int>(std::is_fundamental<T>::value);
00176 };
00177 
00178 template<typename T>
00179 class Block_internal_IsPointer {
00180   template<typename U> friend class Block;
00181   static constexpr int value = static_cast<int>(std::is_pointer<T>::value);
00182 };
00183 
00184 #endif // __cplusplus < 201103L
00185 
00186 
00187 
00188 // <summary>simple 1-D array</summary>
00189 // <use visibility=export>
00190 //
00191 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00192 // </reviewed>
00193 //
00194 // <etymology>
00195 //     This should be viewed as a <em>block</em> of memory without sophisticated
00196 //     manipulation functions. Thus it is called <src>Block</src>.
00197 // </etymology>
00198 //
00199 // <synopsis>
00200 // <src>Block<T></src> is a simple templated 1-D array class. Indices are always
00201 // 0-based. For efficiency reasons, no index checking is done unless the
00202 // preprocessor symbol <src>AIPS_ARRAY_INDEX_CHECK</src> is defined. 
00203 // <src>Block<T></src>'s may be assigned to and constructed from other
00204 // <src>Block<T></src>'s.
00205 // As no reference counting is done this can be an expensive operation, however.
00206 //
00207 // The net effect of this class is meant to be unsurprising to users who think
00208 // of arrays as first class objects. The name "Block" is  intended to convey
00209 // the concept of a solid "chunk" of things without any intervening "fancy"
00210 // memory management, etc. This class was written to be
00211 // used in the implementations of more functional Vector, Matrix, etc. classes,
00212 // although it is expected <src>Block<T></src> will be useful on its own.
00213 //
00214 // The Block class should be efficient. You should normally use <src>Block</src>.
00215 //
00216 // <note role=warning> If you use the assignment operator on an element of this
00217 // class, you may leave dangling references to pointers released from
00218 // <src>storage()</src>.
00219 // Resizing the array will also have this effect if the underlying storage
00220 // is actually affected.
00221 // </note>
00222 //
00223 // If index checking is turned on, an out-of-bounds index will
00224 // generate an <src>indexError<uInt></src> exception.
00225 // </synopsis>
00226 //
00227 // <example> 
00228 // <srcblock>
00229 // Block<Int> a(100,0);  // 100 ints initialized to 0
00230 // Block<Int> b;         // 0-length Block
00231 // // ...
00232 // b = a;                // resize b and copy a into it
00233 // for (size_t i=0; i < a.nelements(); i++) {
00234 //     a[i] = i;    // Generate a sequence
00235 //                  // with Vectors, could simply say "indgen(myVector);"
00236 // }
00237 // b.set(-1);       // All positions in b have the value -1
00238 // b.resize(b.nelements()*2); // Make b twice as long, by default the old
00239 //                            // elements are copied over, although this can
00240 //                            // be defeated.
00241 // some_c_function(b.storage());  // Use a fn that takes an
00242 //                                // <src>Int *</src> pointer
00243 // </srcblock> 
00244 // </example>
00245 //
00246 template<class T> class Block: public BlockTrace
00247 {
00248 public:
00249   // Create a zero-length Block. Note that any index into this Block
00250   // is an error.
00251   // DefaultAllocator<T> is used as an allocator.
00252   Block() :
00253       allocator_p(get_allocator<typename DefaultAllocator<T>::type>()), capacity_p(
00254           0), used_p(0), array(0), destroyPointer(True), keep_allocator_p(False) {
00255   }
00256   // Create a zero-length Block. Note that any index into this Block
00257   // is an error.
00258   template<typename Allocator>
00259   explicit Block(AllocSpec<Allocator> const &) :
00260       allocator_p(get_allocator<typename Allocator::type>()), capacity_p(0), used_p(
00261           0), array(0), destroyPointer(True), keep_allocator_p(False) {
00262   }
00263 
00264   // Create a Block with the given number of points. The values in Block
00265   // are initialized. Note that indices range between 0 and n-1.
00266   // DefaultAllocator<T> is used as an allocator.
00267   explicit Block(size_t n) :
00268       allocator_p(get_allocator<typename DefaultAllocator<T>::type>()), used_p(
00269           n), destroyPointer(True), keep_allocator_p(False) {
00270     init(init_anyway() ? ArrayInitPolicy::INIT : ArrayInitPolicy::NO_INIT);
00271   }
00272 
00273   // Create a Block with the given number of points. The values in Block
00274   // are initialized. Note that indices range between 0 and n-1.
00275   template<typename Allocator>
00276   Block(size_t n, AllocSpec<Allocator> const &) :
00277       allocator_p(get_allocator<typename Allocator::type>()), used_p(n), destroyPointer(
00278           True), keep_allocator_p(False) {
00279     init(init_anyway() ? ArrayInitPolicy::INIT : ArrayInitPolicy::NO_INIT);
00280   }
00281 
00282   // Create a Block with the given number of points. The values in Block
00283   // are uninitialized. Note that indices range between 0 and n-1.
00284   // DefaultAllocator<T> is used as an allocator.
00285   Block(size_t n, ArrayInitPolicy initPolicy) :
00286       allocator_p(get_allocator<typename DefaultAllocator<T>::type>()), used_p(
00287           n), destroyPointer(True), keep_allocator_p(False) {
00288     init(initPolicy);
00289   }
00290 
00291   // Create a Block with the given number of points.
00292   // Note that indices range between 0 and n-1.
00293   template<typename Allocator>
00294   Block(size_t n, ArrayInitPolicy initPolicy,
00295       AllocSpec<Allocator> const &) :
00296       allocator_p(get_allocator<typename Allocator::type>()), used_p(n), destroyPointer(
00297           True), keep_allocator_p(False) {
00298     init(initPolicy);
00299   }
00300 
00301   // Create a Block of the given length, and initialize (via copy constructor for 
00302   // objects of type T) with the provided value.
00303   // DefaultAllocator<T> is used as an allocator.
00304   Block(size_t n, T const &val) :
00305       allocator_p(get_allocator<typename DefaultAllocator<T>::type>()), used_p(
00306           n), destroyPointer(True), keep_allocator_p(False) {
00307     init(ArrayInitPolicy::NO_INIT);
00308     try {
00309       allocator_p->construct(array, get_size(), val);
00310     } catch (...) {
00311       dealloc();
00312       throw;
00313     }
00314   }
00315 
00316   // Create a Block of the given length, and initialize (via copy constructor for
00317   // objects of type T) with the provided value.
00318   template<typename Allocator>
00319   Block(size_t n, T const &val, AllocSpec<Allocator> const &) :
00320       allocator_p(get_allocator<typename Allocator::type>()), used_p(n), destroyPointer(
00321           True), keep_allocator_p(False) {
00322     init(ArrayInitPolicy::NO_INIT);
00323     try {
00324       allocator_p->construct(array, get_size(), val);
00325     } catch (...) {
00326       dealloc();
00327       throw;
00328     }
00329   }
00330 
00331   // Create a <src>Block</src> from a C-array (i.e. pointer). If 
00332   // <src>takeOverStorage</src> is <src>True</src>, The Block assumes that
00333   // it owns the pointer, i.e. that it is safe to release it via <src>allocator</src> when
00334   // the Block is destructed, otherwise the actual storage is not destroyed.
00335   // If true, <src>storagePointer</src> is set to <src>0</src>.
00336   // It is strongly recommended to supply an appropriate <src>allocator</src> argument explicitly
00337   // whenever <src>takeOverStorage</src> == True
00338   // to let <src>Block</src> to know how to release the <src>storagePointer</src>.
00339   // The default allocator set by this constructor will be changed from <src>NewDelAllocator<T>::value</src>
00340   // to <src>DefaultAllocator<T>::value</src> in future.
00341   Block(size_t n, T *&storagePointer, Bool takeOverStorage = True) :
00342       allocator_p(get_allocator<typename NewDelAllocator<T>::type>()), capacity_p(
00343           n), used_p(n), array(storagePointer), destroyPointer(takeOverStorage), keep_allocator_p(
00344           False) {
00345     if (destroyPointer)
00346       storagePointer = 0;
00347   }
00348   // Create a <src>Block</src> from a C-array (i.e. pointer). If
00349   // <src>takeOverStorage</src> is <src>True</src>, The Block assumes that
00350   // it owns the pointer, i.e. that it is safe to release it via <src>allocator</src> when
00351   // the Block is destructed, otherwise the actual storage is not destroyed.
00352   // If true, <src>storagePointer</src> is set to <src>0</src>.
00353   template<typename Allocator>
00354   Block(size_t n, T *&storagePointer, Bool takeOverStorage,
00355       AllocSpec<Allocator> const &) :
00356       allocator_p(get_allocator<typename Allocator::type>()), capacity_p(n), used_p(
00357           n), array(storagePointer), destroyPointer(takeOverStorage), keep_allocator_p(
00358           False) {
00359     if (destroyPointer)
00360       storagePointer = 0;
00361   }
00362 
00363   // Copy the other block into this one. Uses copy, not reference, semantics.
00364   Block(const Block<T> &other) :
00365       allocator_p(other.allocator_p), used_p(other.size()), destroyPointer(
00366           True), keep_allocator_p(False) {
00367     init(ArrayInitPolicy::NO_INIT);
00368 
00369     try {
00370       //objcopy(array, other.array, get_size());
00371       objthrowcp1(array, other.array, get_size());
00372       allocator_p->construct(array, get_size(), other.array);
00373     } catch (...) {
00374       dealloc();
00375       throw;
00376     }
00377   }
00378   
00379   // Assign other to this. this resizes itself to the size of other, so after
00380   // the assignment, this->nelements() == other.nelements() always.
00381   Block<T> &operator=(const Block<T> &other) {
00382     if (&other != this) {
00383       T *old = array;
00384       this->resize(other.size(), True, False, ArrayInitPolicy::NO_INIT);
00385       if (array == old) {
00386         objcopy(array, other.array, get_size());
00387       } else {
00388         objthrowcp1(array, other.array, get_size());
00389         allocator_p->construct(array, get_size(), other.array);
00390       }
00391     }
00392     return *this;
00393   }
00394   
00395   // Frees up the storage pointed contained in the Block.
00396   ~Block() {
00397     deinit();
00398   }
00399 
00400   // Resizes the Block. If <src>n == nelements()</src> resize just returns. If
00401   // a larger size is requested (<src>n > nelements()</src>) the Block always
00402   // resizes. If the requested size is smaller (<src>n < nelements()</src>),
00403   // by default the Block does not resize smaller, although it can be
00404   // forced to with <src>forceSmaller</src>. The reasoning behind this is that
00405   // often the user will just want a buffer of at least a certain size,
00406   // and won't want to pay the cost of multiple resizings.
00407   // <srcblock>
00408   // Block<float> bf(100, 0.0);
00409   // bf.resize(10);        // bf.nelements() == 100
00410   // bf.resize(10, True)   // bf.nelements() == 10
00411   // bf.resize(200)        // bf.nelements() == 200
00412   // </srcblock>
00413   // Normally the old elements are copied over (although if the
00414   // Block is lengthened the trailing elements will have undefined
00415   // values), however this can be turned off by setting copyElements to
00416   // False.
00417   //
00418   // This is written as three functions because default parameters do
00419   // not always work properly with templates.
00420   //
00421   // <src>initPolicy</src> makes sense to determine whether extended elements
00422   // should be initialized or not when you enlarge Block.
00423   // <group>
00424   void resize(size_t n, Bool forceSmaller = False, Bool copyElements = True) {
00425     resize(n, forceSmaller, copyElements,
00426         init_anyway() ? ArrayInitPolicy::INIT : ArrayInitPolicy::NO_INIT);
00427   }
00428   void resize(size_t n, Bool forceSmaller, Bool copyElements,
00429       ArrayInitPolicy initPolicy) {
00430     if (n == get_size()) {
00431       return;
00432     }
00433     if (n < get_size() && forceSmaller == False) {
00434       if (false) { // to keep get_size() == get_capacity()
00435         allocator_p->destroy(&array[n], get_size() - n);
00436         set_size(n);
00437       }
00438       return;
00439     }
00440     if (get_size() < n  && n <= get_capacity()) {
00441       allocator_p->construct(&array[get_size()], n - get_size());
00442       set_size(n);
00443       return;
00444     }
00445     T *tp = n > 0 ? allocator_p->allocate(n) : 0;
00446     traceAlloc(tp, n);
00447     if (n > 0) {
00448       size_t start = 0;
00449       if (copyElements) {
00450         size_t nmin = std::min(get_size(), n);  // Don't copy too much!
00451         if (nmin > 0) {
00452           try {
00453             allocator_p->construct(tp, nmin, array);
00454           } catch (...) {
00455             traceFree(tp, n);
00456             allocator_p->deallocate(tp, n);
00457             throw;
00458           }
00459         }
00460         start = nmin;
00461       }
00462       if (initPolicy == ArrayInitPolicy::INIT) {
00463         try {
00464           allocator_p->construct(&tp[start], n - start);
00465         } catch (...) {
00466           allocator_p->destroy(tp, start);
00467           traceFree(tp, n);
00468           allocator_p->deallocate(tp, n);
00469           throw;
00470         }
00471       }
00472     }
00473     deinit();
00474     destroyPointer = True;
00475     array = tp;                       // ... and update pointer
00476     set_capacity(n);
00477     set_size(n);
00478   }
00479   // </group>
00480 
00481   // Remove a single element from the Block. If forceSmaller is True this
00482   // will resize the Block and hence involve new memory allocations. This is
00483   // relatively expensive so setting forceSmaller to False is preferred. When
00484   // forceSmaller is False the Block is not resized but the elements with an
00485   // index above the removed element are shuffled down by one. For backward
00486   // compatibility forceSmaller is True by default.
00487   //
00488   // <src>initPolicy</src> makes sense to determine whether new storage
00489   // should be initialized or not before copying when <src>forceSmaller</src> is True.
00490   // <group>
00491   void remove(size_t whichOne, Bool forceSmaller = True) {
00492     remove(whichOne, forceSmaller,
00493         init_anyway() ? ArrayInitPolicy::INIT : ArrayInitPolicy::NO_INIT);
00494   }
00495   void remove(size_t whichOne, Bool forceSmaller, ArrayInitPolicy initPolicy) {
00496     if (whichOne >= get_size()) {
00497 #if defined(AIPS_ARRAY_INDEX_CHECK)
00498       throw(indexError<uInt>(whichOne, "Block::remove() - "
00499                              "index out of range"));
00500 #else
00501       return;
00502 #endif
00503     }
00504     size_t n = get_size() - 1;
00505     if (forceSmaller == True) {
00506       T *tp = n > 0 ? allocator_p->allocate(n) : 0;
00507       traceAlloc(array, n);
00508       if (initPolicy == ArrayInitPolicy::INIT && n > 0) {
00509         try {
00510           allocator_p->construct(tp, n);
00511         } catch (...) {
00512           traceFree(tp, n);
00513           allocator_p->deallocate(tp, n);
00514           throw;
00515         }
00516       }
00517       try {
00518         objcopy(tp, array, whichOne);
00519       } catch (...) {
00520         traceFree(tp, n);
00521         allocator_p->deallocate(tp, n);
00522         throw;
00523       }
00524       try {
00525         objcopy(tp + whichOne, array + whichOne + 1, get_size() - whichOne - 1);
00526       } catch (...) {
00527         allocator_p->destroy(tp, whichOne);
00528         traceFree(tp, n);
00529         allocator_p->deallocate(tp, n);
00530         throw;
00531       }
00532       if (array && destroyPointer) {
00533         traceFree(array, get_capacity());
00534         allocator_p->destroy(array, get_size());
00535         allocator_p->deallocate(array, get_capacity());
00536         array = 0;
00537       };
00538       set_capacity(n);
00539       set_size(n);
00540       array = tp;
00541       destroyPointer = True;
00542     } else {
00543       objmove(&array[whichOne], &array[whichOne + 1], get_size() - whichOne - 1);
00544       if (false) { // to keep get_size() == get_capacity()
00545         allocator_p->destroy(&array[n], 1);
00546         set_size(n);
00547       }
00548     }
00549   }
00550   // </group>
00551 
00552   // Prohibit changing allocator for this instance.
00553   // <group>
00554   void prohibitChangingAllocator() {
00555     keep_allocator_p = True;
00556   }
00557   // Permit changing allocator for this instance.
00558   void permitChangingAllocator() {
00559     keep_allocator_p = False;
00560   }
00561   // </group>
00562 
00563   // Replace the internal storage with a C-array (i.e. pointer).
00564   // If <src>takeOverStorage</src> is True, The Block assumes that it
00565   // owns the pointer, i.e. that it is safe to release it via <src>allocator</src> when the
00566   // <src>Block</src>is destructed, otherwise the actual storage is not destroyed.
00567   // If true, storagePointer is set to <src>NULL</src>.
00568   // It is strongly recommended to supply an appropriate <src>allocator</src> argument explicitly
00569   // whenever <src>takeOverStorage</src> == True
00570   // to let <src>Block</src> to know how to release the <src>storagePointer</src>.
00571   // The default parameter of allocator will be changed from <src>AllocSpec<NewDelAllocator<T> >::value</src>
00572   // to <src>AllocSpec<DefaultAllocator<T> >::value</src> in future.
00573   // AipsError is thrown if allocator is incompatible with the current allocator of the instance and changing allocator is prohibited,
00574   // even if takeOverStorage == False.
00575   // <group>
00576   void replaceStorage(size_t n, T *&storagePointer, Bool takeOverStorage=True) {
00577     replaceStorage(n, storagePointer, takeOverStorage, AllocSpec<NewDelAllocator<T> >::value);
00578         }
00579   template<typename Allocator>
00580   void replaceStorage(size_t n, T *&storagePointer, Bool takeOverStorage, AllocSpec<Allocator> const &) {
00581     if (keep_allocator_p && ! isCompatibleAllocator<Allocator>()) {
00582       throw AipsError("Block::replaceStorage - Attemption to change allocator of Block");
00583     }
00584 
00585     if (array && destroyPointer) {
00586       traceFree (array, get_capacity());
00587       allocator_p->destroy(array, get_size());
00588       allocator_p->deallocate(array, get_capacity());
00589       array = 0;
00590     };
00591     set_capacity(n);
00592     set_size(n);
00593     allocator_p = get_allocator<typename Allocator::type>();
00594     array = storagePointer;
00595     destroyPointer = takeOverStorage;
00596     if (destroyPointer) storagePointer = 0;
00597   }
00598   // </group>
00599 
00600   // Index into the block (0-based). If the preprocessor symbol
00601   // <src>AIPS_ARRAY_INDEX_CHECK</src> is defined, index checking will be done
00602   // and an out-of-bounds index will cause an <src>indexError<uInt></src> to be
00603   // thrown. Note that valid indices range between 0 and <src>nelements()-1</src>.
00604   // <thrown>
00605   //    <li> indexError
00606   // </thrown>
00607   // <group>
00608   T &operator[](size_t index) {
00609 #if defined(AIPS_ARRAY_INDEX_CHECK)
00610     // Write it this way to avoid casts; remember index and get_size() are
00611     // unsigned.
00612     if ((get_size() == 0) || (index > get_size() - 1)) {
00613       throw(indexError<uInt>(index, "Block::operator[] - "
00614                              "index out of range"));
00615     };
00616 #endif
00617     return array[index];
00618   }
00619   const T &operator[](size_t index) const {
00620 #if defined(AIPS_ARRAY_INDEX_CHECK)
00621     if ((get_size() == 0) || (index > get_size() - 1)) {
00622       throw(indexError<uInt>(index, "Block::operator[] const - "
00623                              "index out of range"));
00624     };
00625 #endif
00626     return array[index];
00627   }
00628   // </group>
00629   
00630   // Set all values in the block to "val".
00631   // <group>
00632   Block<T> &operator=(const T &val)
00633     { T tmp=val; objset(array, tmp, get_size()); return *this;}
00634   void set(const T &val) { *this = val; }
00635   // </group>
00636 
00637   // If you really, really, need a "raw" pointer to the beginning of the
00638   // storage area this will give it to you. This may leave dangling pointers
00639   // if the block is destructed or if the assignment operator or resize 
00640   // is used. Returns a null pointer if <src>nelements() == 0</src>.
00641   // It is best to only use this if you completely control the extent and
00642   // lifetime of the <src>Block</src>.
00643   // <h3> Examples of misuse </h3> <srcblock>
00644   // Block<Int> *bp = new Block<Int>(100);
00645   // Int *ip = bp->storage();
00646   // DefaultAllocator<Int>::value.deallocate(bp, bp->capacity());   // Oops, ip is now dangling
00647   // Block<Int> a(100),b(100);
00648   // Int *ip = a.storage();
00649   // a = b;          // Likewise
00650   // </srcblock>
00651   // <group>
00652   T *storage() {return array;}
00653   const T *storage() const {return array;}
00654   // </group>
00655 
00656   // The number of elements contained in this <src>Block<T></src>.
00657   // <group>
00658   size_t nelements() const {return size();}
00659   size_t size() const {return get_capacity();}
00660   // </group>
00661 
00662   // The capacity in this <src>Block<T></src>.
00663   // <src>size() <= capacity()</src> is always true.
00664   size_t capacity() const {return get_capacity();}
00665 
00666   // Is the block empty (i.e. no elements)?
00667   Bool empty() const {return size() == 0;}
00668 
00669   // Define the STL-style iterators.
00670   // It makes it possible to iterate through all data elements.
00671   // <srcblock>
00672   //  Block<Int> bl(100,0);
00673   //  for (Block<Int>::iterator iter=bl.begin(); iter!=bl.end(); iter++) {
00674   //    *iter += 1;
00675   //  }
00676   // </srcblock>
00677   // <group name=STL-iterator>
00678   // STL-style typedefs.
00679   // <group>
00680   typedef T                 value_type;
00681   typedef T*                iterator;
00682   typedef const T*          const_iterator;
00683   typedef value_type*       pointer;
00684   typedef const value_type* const_pointer; 
00685   typedef value_type&       reference;
00686   typedef const value_type& const_reference;
00687   typedef size_t            size_type;
00688   typedef ptrdiff_t         difference_type;
00689   // </group>
00690   // Get the begin and end iterator object for this block.
00691   // <group>
00692   iterator begin()
00693     { return array; }
00694   const_iterator begin() const
00695     { return array; }
00696   iterator end()
00697     { return array + size(); }
00698   const_iterator end() const
00699     { return array + size(); }
00700   // </group>
00701   // </group>
00702 
00703   inline void traceAlloc (const void* addr, size_t sz) const
00704   {
00705     if (itsTraceSize>0 && sz>=itsTraceSize) {
00706       doTraceAlloc (addr, sz, whatType(static_cast<T*>(0)), sizeof(T));
00707     }
00708   }
00709   inline void traceFree (const void* addr, size_t sz) const
00710   {
00711     if (itsTraceSize>0 && sz>=itsTraceSize) {
00712       doTraceFree (addr, sz, whatType(static_cast<T*>(0)), sizeof(T));
00713     }
00714   }
00715 
00716  private:
00717   friend class Array<T>; // to allow access to following constructors.
00718 
00719   Block(size_t n, ArrayInitPolicy initPolicy,
00720           Allocator_private::BulkAllocator<T> *allocator) :
00721       allocator_p(allocator), used_p(n), destroyPointer(
00722           True), keep_allocator_p(False) {
00723     init(initPolicy);
00724   }
00725   Block(size_t n, Allocator_private::AllocSpec<T> allocator) :
00726       allocator_p(allocator.allocator), used_p(n), destroyPointer(
00727           True), keep_allocator_p(False) {
00728     init(init_anyway() ? ArrayInitPolicy::INIT : ArrayInitPolicy::NO_INIT);
00729   }
00730   Block(size_t n, T *&storagePointer, Bool takeOverStorage,
00731           Allocator_private::BulkAllocator<T> *allocator) :
00732       allocator_p(allocator), capacity_p(n), used_p(
00733           n), array(storagePointer), destroyPointer(takeOverStorage), keep_allocator_p(
00734           False) {
00735     if (destroyPointer)
00736       storagePointer = 0;
00737   }
00738   void construct(size_t pos, size_t n, T const *src) {
00739     allocator_p->construct(&array[pos], n, src);
00740   }
00741   void construct(size_t pos, size_t n,
00742       T const &initial_value) {
00743     allocator_p->construct(&array[pos], n, initial_value);
00744   }
00745   void construct(size_t pos, size_type n) {
00746     allocator_p->construct(&array[pos], n);
00747   }
00748   void destroy(size_t pos, size_type n) {
00749     allocator_p->destroy(&array[pos], n);
00750   }
00751   Allocator_private::BulkAllocator<T> *get_allocator(){
00752       return allocator_p;
00753   }
00754 
00755   static bool init_anyway() {
00756      return !(Block_internal_IsFundamental<T>::value
00757          || Block_internal_IsPointer<T>::value);
00758    }
00759 
00760   // end of friend
00761 
00762   void init(ArrayInitPolicy initPolicy) {
00763     set_capacity(get_size());
00764     if (get_capacity() > 0) {
00765       array = allocator_p->allocate(get_capacity());
00766       traceAlloc(array, get_capacity());
00767       if (initPolicy == ArrayInitPolicy::INIT) {
00768         try {
00769           allocator_p->construct(array, get_size());
00770         } catch (...) {
00771           dealloc();
00772           throw;
00773         }
00774       }
00775     } else {
00776       array = 0;
00777     }
00778   }
00779 
00780   void deinit() {
00781     if (array && destroyPointer) {
00782       allocator_p->destroy(array, get_size());
00783       dealloc();
00784     }
00785   }
00786   void dealloc() {
00787     if (array && destroyPointer) {
00788       traceFree(array, get_capacity());
00789       allocator_p->deallocate(array, get_capacity());
00790       array = 0;
00791     }
00792   }
00793 
00794   template<typename Allocator>
00795   static typename Allocator_private::BulkAllocator<
00796       typename Allocator::value_type> *get_allocator() {
00797     return Allocator_private::get_allocator<
00798         Allocator>();
00799   }
00800 
00801   template<typename Allocator>
00802   Bool isCompatibleAllocator() {
00803     typename Allocator_private::BulkAllocator<
00804         typename Allocator::type::value_type> *other_allocator =
00805                 Allocator_private::get_allocator<typename Allocator::type>();
00806     return other_allocator == allocator_p;
00807   }
00808 
00809   // The number of used elements in the vector
00810   size_t get_size() const { return used_p;}
00811   // Set the number of used elements in the vector
00812   void set_size(size_t new_value) {
00813     AlwaysAssert(new_value <= get_capacity(), AipsError);
00814     used_p = new_value;
00815   }
00816   // The capacity of the vector
00817   size_t get_capacity() const { return capacity_p;}
00818   // Set the capacity of the vector
00819   void set_capacity(size_t new_value) {
00820     capacity_p = new_value;
00821     set_size(std::min(get_size(), capacity_p));
00822   }
00823 
00824   // The allocator
00825   typename Allocator_private::BulkAllocator<T> *allocator_p;
00826   // The capacity of the vector
00827   size_t capacity_p;
00828   // The number of used elements in the vector
00829   size_t used_p;
00830   // The actual storage
00831   T *array;
00832   // Can we delete the storage upon destruction?
00833   Bool destroyPointer;
00834   // Can we change allocator or not?
00835   Bool keep_allocator_p;
00836 };
00837 
00838 
00839 // <summary>
00840 // A drop-in replacement for <src>Block<T*></src>.
00841 // </summary>
00842  
00843 // <use visibility=export>
00844 // <prerequisite>
00845 //   <li> <linkto class=Block>Block</linkto>
00846 // </prerequisite>
00847  
00848 // <synopsis>
00849 // <src>PtrBlock<T*></src> has exactly the same interface as <src>Block<T*></src>
00850 // and should be used in preference to the latter. It's purpose is solely to
00851 // reduce the number of template instantiations.
00852 // </synopsis>
00853  
00854 // <todo asof="1996/05/01">
00855 //   <li> Partial template specialization is another implementation choice that 
00856 //        will be possible eventually.
00857 //   <li> It might be useful to have functions that know the template parameter
00858 //        is a pointer, e.g. that delete all the non-null pointers.
00859 // </todo>
00860  
00861  template<class T> class PtrBlock {
00862  public:
00863    PtrBlock() : block_p() {}
00864    explicit PtrBlock(size_t n) : block_p(n) {}
00865    PtrBlock(size_t n, T val) : block_p(n, (void *)val) {}
00866    PtrBlock(size_t n, T *&storagePointer, Bool takeOverStorage = True)
00867      : block_p(n, (void **&)storagePointer, takeOverStorage) {}
00868    PtrBlock(const PtrBlock<T> &other) : block_p(other.block_p) {}
00869    PtrBlock<T> &operator=(const PtrBlock<T> &other)
00870      { block_p = other.block_p; return *this;}
00871    ~PtrBlock() {}
00872    void resize(size_t n, Bool forceSmaller, Bool copyElements)
00873      { block_p.resize(n,forceSmaller, copyElements); }
00874    void resize(size_t n) {block_p.resize(n);}
00875    void resize(size_t n, Bool forceSmaller) {block_p.resize(n, forceSmaller);}
00876    void remove(size_t whichOne, Bool forceSmaller) {
00877      block_p.remove(whichOne, forceSmaller);}
00878    void remove(size_t whichOne) {block_p.remove(whichOne);}
00879    void replaceStorage(size_t n, T *&storagePointer, 
00880                        Bool takeOverStorage=True)
00881      {block_p.replaceStorage(n, (void **&)storagePointer, takeOverStorage);}
00882    T &operator[](size_t index) {return (T &)block_p[index];}
00883    const T &operator[](size_t index) const {return (const T &)block_p[index];}
00884    void set(const T &val) {block_p.set((void *const &)val);}
00885    PtrBlock<T> &operator=(const T &val) {set(val); return *this;}
00886    T *storage()  {return (T *)block_p.storage();}
00887    const T *storage() const {return (const T *)block_p.storage();}
00888    size_t nelements() const {return block_p.nelements();}
00889    size_t size() const {return block_p.size();}
00890    Bool empty() const {return block_p.empty();}
00891  private:
00892    Block<void*> block_p;
00893  };
00894 
00895 
00896 //# Instantiate extern templates for often used types.
00897 #ifdef AIPS_CXX11
00898   extern template class Block<Bool>;
00899   extern template class Block<Char>;
00900   extern template class Block<Short>;
00901   extern template class Block<uShort>;
00902   extern template class Block<Int>;
00903   extern template class Block<uInt>;
00904   extern template class Block<Int64>;
00905   extern template class Block<Float>;
00906   extern template class Block<Double>;
00907   extern template class Block<Complex>;
00908   extern template class Block<DComplex>;
00909   extern template class Block<String>;
00910   extern template class Block<void*>;
00911 #endif
00912 
00913 
00914 } //# NAMESPACE CASACORE - END
00915 
00916 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 31 Aug 2016 for casa by  doxygen 1.6.1