casacore
Block.h
Go to the documentation of this file.
1 //# Block.h: Simple templated array classes
2 //# Copyright (C) 1993-1997,2000,2002,2005,2015
3 //# Associated Universities, Inc. Washington DC, USA.
4 //# National Astronomical Observatory of Japan
5 //# 2-21-1, Osawa, Mitaka, Tokyo, 181-8588, Japan.
6 //#
7 //# This library is free software; you can redistribute it and/or modify it
8 //# under the terms of the GNU Library General Public License as published by
9 //# the Free Software Foundation; either version 2 of the License, or (at your
10 //# option) any later version.
11 //#
12 //# This library is distributed in the hope that it will be useful, but WITHOUT
13 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
15 //# License for more details.
16 //#
17 //# You should have received a copy of the GNU Library General Public License
18 //# along with this library; if not, write to the Free Software Foundation,
19 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
20 //#
21 //# Correspondence concerning AIPS++ should be addressed as follows:
22 //# Internet email: aips2-request@nrao.edu.
23 //# Postal address: AIPS++ Project Office
24 //# National Radio Astronomy Observatory
25 //# 520 Edgemont Road
26 //# Charlottesville, VA 22903-2475 USA
27 //#
28 //# $Id$
29 
30 #ifndef CASA_BLOCK_H
31 #define CASA_BLOCK_H
32 
33 #include <casacore/casa/aips.h>
34 #include <casacore/casa/Utilities/Assert.h>
35 #include <casacore/casa/Utilities/Copy.h>
36 #include <casacore/casa/Utilities/DataType.h>
37 #include <casacore/casa/Containers/Allocator.h>
38 #include <cstddef> // for ptrdiff_t
39 #include <algorithm> // for std:min/max
40 #if __cplusplus < 201103L
41 #include <cwchar>
42 #else
43 #include <type_traits>
44 #endif
45 
46 //# For index checking
47 #if defined(AIPS_ARRAY_INDEX_CHECK)
48 #include <casacore/casa/Exceptions/Error.h>
49 #endif
50 
51 namespace casacore { //# NAMESPACE CASACORE - BEGIN
52 
53 // <summary>simple 1-D array</summary>
54 // <use visibility=export>
55 //
56 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
57 // </reviewed>
58 //
59 // <etymology>
60 // This should be viewed as a <em>block</em> of memory without sophisticated
61 // manipulation functions. Thus it is called <src>Block</src>.
62 // </etymology>
63 //
64 // <synopsis>
65 // <src>Block<T></src> is a simple templated 1-D array class. Indices are always
66 // 0-based. For efficiency reasons, no index checking is done unless the
67 // preprocessor symbol <src>AIPS_ARRAY_INDEX_CHECK</src> is defined.
68 // <src>Block<T></src>'s may be assigned to and constructed from other
69 // <src>Block<T></src>'s.
70 // As no reference counting is done this can be an expensive operation, however.
71 //
72 // The net effect of this class is meant to be unsurprising to users who think
73 // of arrays as first class objects. The name "Block" is intended to convey
74 // the concept of a solid "chunk" of things without any intervening "fancy"
75 // memory management, etc. This class was written to be
76 // used in the implementations of more functional Vector, Matrix, etc. classes,
77 // although it is expected <src>Block<T></src> will be useful on its own.
78 //
79 // The Block class should be efficient. You should normally use <src>Block</src>.
80 //
81 // <note role=warning> If you use the assignment operator on an element of this
82 // class, you may leave dangling references to pointers released from
83 // <src>storage()</src>.
84 // Resizing the array will also have this effect if the underlying storage
85 // is actually affected.
86 // </note>
87 //
88 // If index checking is turned on, an out-of-bounds index will
89 // generate an <src>indexError<uInt></src> exception.
90 // </synopsis>
91 //
92 // <example>
93 // <srcblock>
94 // Block<Int> a(100,0); // 100 ints initialized to 0
95 // Block<Int> b; // 0-length Block
96 // // ...
97 // b = a; // resize b and copy a into it
98 // for (size_t i=0; i < a.nelements(); i++) {
99 // a[i] = i; // Generate a sequence
100 // // with Vectors, could simply say "indgen(myVector);"
101 // }
102 // b.set(-1); // All positions in b have the value -1
103 // b.resize(b.nelements()*2); // Make b twice as long, by default the old
104 // // elements are copied over, although this can
105 // // be defeated.
106 // some_c_function(b.storage()); // Use a fn that takes an
107 // // <src>Int *</src> pointer
108 // </srcblock>
109 // </example>
110 //
112 {
113 public:
114  // Set the trace size. The (de)allocation of Blocks with >= sz elements
115  // will be traced using the MemoryTrace class.
116  // A value 0 means no tracing.
117  static void setTraceSize (size_t sz);
118 protected:
119  // Write alloc and free trace messages.
120  static void doTraceAlloc (const void* addr, size_t nelem,
121  DataType type, size_t sz);
122  static void doTraceFree (const void* addr, size_t nelem,
123  DataType type, size_t sz);
124 protected:
125  static size_t itsTraceSize;
126 };
127 
128 template<typename T> class Block;
129 
130 #if __cplusplus < 201103L
131 
132 template<typename T>
134  template<typename U> friend class Block;
135  enum {value = 0};
136 };
137 
138 template<typename T>
140  template<typename U> friend class Block;
141  enum {value = 0};
142 };
143 
144 #define CASA_TMP_939727(x) template<> class Block_internal_IsFundamental<x> { template<typename U> friend class Block; enum { value = 1 }; }
145 CASA_TMP_939727(void);
146 /*
147 CASA_TMP_939727(char16_t);
148 CASA_TMP_939727(char32_t);
149 */
150 CASA_TMP_939727(bool);
151 CASA_TMP_939727(wchar_t);
152 CASA_TMP_939727(signed char);
153 CASA_TMP_939727(unsigned char);
154 CASA_TMP_939727(float);
155 CASA_TMP_939727(double);
156 CASA_TMP_939727(long double);
157 #define CASA_TMP_939727_int(x) CASA_TMP_939727(x); CASA_TMP_939727(unsigned x)
159 CASA_TMP_939727_int(long int);
160 CASA_TMP_939727_int(long long int);
161 #undef CASA_TMP_939727_int
162 #undef CASA_TMP_939727
163 
164 template<typename T>
166  template<typename U> friend class Block;
167  enum { value = 1 };
168 };
169 
170 #else // __cplusplus < 201103L
171 
172 template<typename T>
174  template<typename U> friend class Block;
175  static constexpr int value = static_cast<int>(std::is_fundamental<T>::value);
176 };
177 
178 template<typename T>
180  template<typename U> friend class Block;
181  static constexpr int value = static_cast<int>(std::is_pointer<T>::value);
182 };
183 
184 #endif // __cplusplus < 201103L
185 
186 
187 
188 // <summary>simple 1-D array</summary>
189 // <use visibility=export>
190 //
191 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
192 // </reviewed>
193 //
194 // <etymology>
195 // This should be viewed as a <em>block</em> of memory without sophisticated
196 // manipulation functions. Thus it is called <src>Block</src>.
197 // </etymology>
198 //
199 // <synopsis>
200 // <src>Block<T></src> is a simple templated 1-D array class. Indices are always
201 // 0-based. For efficiency reasons, no index checking is done unless the
202 // preprocessor symbol <src>AIPS_ARRAY_INDEX_CHECK</src> is defined.
203 // <src>Block<T></src>'s may be assigned to and constructed from other
204 // <src>Block<T></src>'s.
205 // As no reference counting is done this can be an expensive operation, however.
206 //
207 // The net effect of this class is meant to be unsurprising to users who think
208 // of arrays as first class objects. The name "Block" is intended to convey
209 // the concept of a solid "chunk" of things without any intervening "fancy"
210 // memory management, etc. This class was written to be
211 // used in the implementations of more functional Vector, Matrix, etc. classes,
212 // although it is expected <src>Block<T></src> will be useful on its own.
213 //
214 // The Block class should be efficient. You should normally use <src>Block</src>.
215 //
216 // <note role=warning> If you use the assignment operator on an element of this
217 // class, you may leave dangling references to pointers released from
218 // <src>storage()</src>.
219 // Resizing the array will also have this effect if the underlying storage
220 // is actually affected.
221 // </note>
222 //
223 // If index checking is turned on, an out-of-bounds index will
224 // generate an <src>indexError<uInt></src> exception.
225 // </synopsis>
226 //
227 // <example>
228 // <srcblock>
229 // Block<Int> a(100,0); // 100 ints initialized to 0
230 // Block<Int> b; // 0-length Block
231 // // ...
232 // b = a; // resize b and copy a into it
233 // for (size_t i=0; i < a.nelements(); i++) {
234 // a[i] = i; // Generate a sequence
235 // // with Vectors, could simply say "indgen(myVector);"
236 // }
237 // b.set(-1); // All positions in b have the value -1
238 // b.resize(b.nelements()*2); // Make b twice as long, by default the old
239 // // elements are copied over, although this can
240 // // be defeated.
241 // some_c_function(b.storage()); // Use a fn that takes an
242 // // <src>Int *</src> pointer
243 // </srcblock>
244 // </example>
245 //
246 template<class T> class Block: public BlockTrace
247 {
248 public:
249  // Create a zero-length Block. Note that any index into this Block
250  // is an error.
251  // DefaultAllocator<T> is used as an allocator.
252  Block() :
253  allocator_p(get_allocator<typename DefaultAllocator<T>::type>()), capacity_p(
254  0), used_p(0), array(0), destroyPointer(True), keep_allocator_p(False) {
255  }
256  // Create a zero-length Block. Note that any index into this Block
257  // is an error.
258  template<typename Allocator>
259  explicit Block(AllocSpec<Allocator> const &) :
260  allocator_p(get_allocator<typename Allocator::type>()), capacity_p(0), used_p(
261  0), array(0), destroyPointer(True), keep_allocator_p(False) {
262  }
263 
264  // Create a Block with the given number of points. The values in Block
265  // are initialized. Note that indices range between 0 and n-1.
266  // DefaultAllocator<T> is used as an allocator.
267  explicit Block(size_t n) :
268  allocator_p(get_allocator<typename DefaultAllocator<T>::type>()), used_p(
269  n), destroyPointer(True), keep_allocator_p(False) {
270  init(init_anyway() ? ArrayInitPolicy::INIT : ArrayInitPolicy::NO_INIT);
271  }
272 
273  // Create a Block with the given number of points. The values in Block
274  // are initialized. Note that indices range between 0 and n-1.
275  template<typename Allocator>
276  Block(size_t n, AllocSpec<Allocator> const &) :
277  allocator_p(get_allocator<typename Allocator::type>()), used_p(n), destroyPointer(
278  True), keep_allocator_p(False) {
279  init(init_anyway() ? ArrayInitPolicy::INIT : ArrayInitPolicy::NO_INIT);
280  }
281 
282  // Create a Block with the given number of points. The values in Block
283  // are uninitialized. Note that indices range between 0 and n-1.
284  // DefaultAllocator<T> is used as an allocator.
285  Block(size_t n, ArrayInitPolicy initPolicy) :
286  allocator_p(get_allocator<typename DefaultAllocator<T>::type>()), used_p(
287  n), destroyPointer(True), keep_allocator_p(False) {
288  init(initPolicy);
289  }
290 
291  // Create a Block with the given number of points.
292  // Note that indices range between 0 and n-1.
293  template<typename Allocator>
294  Block(size_t n, ArrayInitPolicy initPolicy,
295  AllocSpec<Allocator> const &) :
296  allocator_p(get_allocator<typename Allocator::type>()), used_p(n), destroyPointer(
297  True), keep_allocator_p(False) {
298  init(initPolicy);
299  }
300 
301  // Create a Block of the given length, and initialize (via copy constructor for
302  // objects of type T) with the provided value.
303  // DefaultAllocator<T> is used as an allocator.
304  Block(size_t n, T const &val) :
305  allocator_p(get_allocator<typename DefaultAllocator<T>::type>()), used_p(
306  n), destroyPointer(True), keep_allocator_p(False) {
308  try {
309  allocator_p->construct(array, get_size(), val);
310  } catch (...) {
311  dealloc();
312  throw;
313  }
314  }
315 
316  // Create a Block of the given length, and initialize (via copy constructor for
317  // objects of type T) with the provided value.
318  template<typename Allocator>
319  Block(size_t n, T const &val, AllocSpec<Allocator> const &) :
320  allocator_p(get_allocator<typename Allocator::type>()), used_p(n), destroyPointer(
321  True), keep_allocator_p(False) {
323  try {
324  allocator_p->construct(array, get_size(), val);
325  } catch (...) {
326  dealloc();
327  throw;
328  }
329  }
330 
331  // Create a <src>Block</src> from a C-array (i.e. pointer). If
332  // <src>takeOverStorage</src> is <src>True</src>, The Block assumes that
333  // it owns the pointer, i.e. that it is safe to release it via <src>allocator</src> when
334  // the Block is destructed, otherwise the actual storage is not destroyed.
335  // If true, <src>storagePointer</src> is set to <src>0</src>.
336  // It is strongly recommended to supply an appropriate <src>allocator</src> argument explicitly
337  // whenever <src>takeOverStorage</src> == True
338  // to let <src>Block</src> to know how to release the <src>storagePointer</src>.
339  // The default allocator set by this constructor will be changed from <src>NewDelAllocator<T>::value</src>
340  // to <src>DefaultAllocator<T>::value</src> in future.
341  Block(size_t n, T *&storagePointer, Bool takeOverStorage = True) :
342  allocator_p(get_allocator<typename NewDelAllocator<T>::type>()), capacity_p(
343  n), used_p(n), array(storagePointer), destroyPointer(takeOverStorage), keep_allocator_p(
344  False) {
345  if (destroyPointer)
346  storagePointer = 0;
347  }
348  // Create a <src>Block</src> from a C-array (i.e. pointer). If
349  // <src>takeOverStorage</src> is <src>True</src>, The Block assumes that
350  // it owns the pointer, i.e. that it is safe to release it via <src>allocator</src> when
351  // the Block is destructed, otherwise the actual storage is not destroyed.
352  // If true, <src>storagePointer</src> is set to <src>0</src>.
353  template<typename Allocator>
354  Block(size_t n, T *&storagePointer, Bool takeOverStorage,
355  AllocSpec<Allocator> const &) :
356  allocator_p(get_allocator<typename Allocator::type>()), capacity_p(n), used_p(
357  n), array(storagePointer), destroyPointer(takeOverStorage), keep_allocator_p(
358  False) {
359  if (destroyPointer)
360  storagePointer = 0;
361  }
362 
363  // Copy the other block into this one. Uses copy, not reference, semantics.
364  Block(const Block<T> &other) :
365  allocator_p(other.allocator_p), used_p(other.size()), destroyPointer(
366  True), keep_allocator_p(False) {
368 
369  try {
370  //objcopy(array, other.array, get_size());
371  objthrowcp1(array, other.array, get_size());
372  allocator_p->construct(array, get_size(), other.array);
373  } catch (...) {
374  dealloc();
375  throw;
376  }
377  }
378 
379  // Assign other to this. this resizes itself to the size of other, so after
380  // the assignment, this->nelements() == other.nelements() always.
381  Block<T> &operator=(const Block<T> &other) {
382  if (&other != this) {
383  T *old = array;
384  this->resize(other.size(), True, False, ArrayInitPolicy::NO_INIT);
385  if (array == old) {
386  objcopy(array, other.array, get_size());
387  } else {
388  objthrowcp1(array, other.array, get_size());
389  allocator_p->construct(array, get_size(), other.array);
390  }
391  }
392  return *this;
393  }
394 
395  // Frees up the storage pointed contained in the Block.
396  ~Block() {
397  deinit();
398  }
399 
400  // Resizes the Block. If <src>n == nelements()</src> resize just returns. If
401  // a larger size is requested (<src>n > nelements()</src>) the Block always
402  // resizes. If the requested size is smaller (<src>n < nelements()</src>),
403  // by default the Block does not resize smaller, although it can be
404  // forced to with <src>forceSmaller</src>. The reasoning behind this is that
405  // often the user will just want a buffer of at least a certain size,
406  // and won't want to pay the cost of multiple resizings.
407  // <srcblock>
408  // Block<float> bf(100, 0.0);
409  // bf.resize(10); // bf.nelements() == 100
410  // bf.resize(10, True) // bf.nelements() == 10
411  // bf.resize(200) // bf.nelements() == 200
412  // </srcblock>
413  // Normally the old elements are copied over (although if the
414  // Block is lengthened the trailing elements will have undefined
415  // values), however this can be turned off by setting copyElements to
416  // False.
417  //
418  // This is written as three functions because default parameters do
419  // not always work properly with templates.
420  //
421  // <src>initPolicy</src> makes sense to determine whether extended elements
422  // should be initialized or not when you enlarge Block.
423  // <group>
424  void resize(size_t n, Bool forceSmaller = False, Bool copyElements = True) {
425  resize(n, forceSmaller, copyElements,
427  }
428  void resize(size_t n, Bool forceSmaller, Bool copyElements,
429  ArrayInitPolicy initPolicy) {
430  if (n == get_size()) {
431  return;
432  }
433  if (n < get_size() && forceSmaller == False) {
434  if (false) { // to keep get_size() == get_capacity()
435  allocator_p->destroy(&array[n], get_size() - n);
436  set_size(n);
437  }
438  return;
439  }
440  if (get_size() < n && n <= get_capacity()) {
441  allocator_p->construct(&array[get_size()], n - get_size());
442  set_size(n);
443  return;
444  }
445  T *tp = n > 0 ? allocator_p->allocate(n) : 0;
446  traceAlloc(tp, n);
447  if (n > 0) {
448  size_t start = 0;
449  if (copyElements) {
450  size_t nmin = std::min(get_size(), n); // Don't copy too much!
451  if (nmin > 0) {
452  try {
453  allocator_p->construct(tp, nmin, array);
454  } catch (...) {
455  traceFree(tp, n);
456  allocator_p->deallocate(tp, n);
457  throw;
458  }
459  }
460  start = nmin;
461  }
462  if (initPolicy == ArrayInitPolicy::INIT) {
463  try {
464  allocator_p->construct(&tp[start], n - start);
465  } catch (...) {
466  allocator_p->destroy(tp, start);
467  traceFree(tp, n);
468  allocator_p->deallocate(tp, n);
469  throw;
470  }
471  }
472  }
473  deinit();
474  destroyPointer = True;
475  array = tp; // ... and update pointer
476  set_capacity(n);
477  set_size(n);
478  }
479  // </group>
480 
481  // Remove a single element from the Block. If forceSmaller is True this
482  // will resize the Block and hence involve new memory allocations. This is
483  // relatively expensive so setting forceSmaller to False is preferred. When
484  // forceSmaller is False the Block is not resized but the elements with an
485  // index above the removed element are shuffled down by one. For backward
486  // compatibility forceSmaller is True by default.
487  //
488  // <src>initPolicy</src> makes sense to determine whether new storage
489  // should be initialized or not before copying when <src>forceSmaller</src> is True.
490  // <group>
491  void remove(size_t whichOne, Bool forceSmaller = True) {
492  remove(whichOne, forceSmaller,
494  }
495  void remove(size_t whichOne, Bool forceSmaller, ArrayInitPolicy initPolicy) {
496  if (whichOne >= get_size()) {
497 #if defined(AIPS_ARRAY_INDEX_CHECK)
498  throw(indexError<uInt>(whichOne, "Block::remove() - "
499  "index out of range"));
500 #else
501  return;
502 #endif
503  }
504  size_t n = get_size() - 1;
505  if (forceSmaller == True) {
506  T *tp = n > 0 ? allocator_p->allocate(n) : 0;
507  traceAlloc(array, n);
508  if (initPolicy == ArrayInitPolicy::INIT && n > 0) {
509  try {
510  allocator_p->construct(tp, n);
511  } catch (...) {
512  traceFree(tp, n);
513  allocator_p->deallocate(tp, n);
514  throw;
515  }
516  }
517  try {
518  objcopy(tp, array, whichOne);
519  } catch (...) {
520  traceFree(tp, n);
521  allocator_p->deallocate(tp, n);
522  throw;
523  }
524  try {
525  objcopy(tp + whichOne, array + whichOne + 1, get_size() - whichOne - 1);
526  } catch (...) {
527  allocator_p->destroy(tp, whichOne);
528  traceFree(tp, n);
529  allocator_p->deallocate(tp, n);
530  throw;
531  }
532  if (array && destroyPointer) {
533  traceFree(array, get_capacity());
534  allocator_p->destroy(array, get_size());
535  allocator_p->deallocate(array, get_capacity());
536  array = 0;
537  };
538  set_capacity(n);
539  set_size(n);
540  array = tp;
541  destroyPointer = True;
542  } else {
543  objmove(&array[whichOne], &array[whichOne + 1], get_size() - whichOne - 1);
544  if (false) { // to keep get_size() == get_capacity()
545  allocator_p->destroy(&array[n], 1);
546  set_size(n);
547  }
548  }
549  }
550  // </group>
551 
552  // Prohibit changing allocator for this instance.
553  // <group>
555  keep_allocator_p = True;
556  }
557  // Permit changing allocator for this instance.
559  keep_allocator_p = False;
560  }
561  // </group>
562 
563  // Replace the internal storage with a C-array (i.e. pointer).
564  // If <src>takeOverStorage</src> is True, The Block assumes that it
565  // owns the pointer, i.e. that it is safe to release it via <src>allocator</src> when the
566  // <src>Block</src>is destructed, otherwise the actual storage is not destroyed.
567  // If true, storagePointer is set to <src>NULL</src>.
568  // It is strongly recommended to supply an appropriate <src>allocator</src> argument explicitly
569  // whenever <src>takeOverStorage</src> == True
570  // to let <src>Block</src> to know how to release the <src>storagePointer</src>.
571  // The default parameter of allocator will be changed from <src>AllocSpec<NewDelAllocator<T> >::value</src>
572  // to <src>AllocSpec<DefaultAllocator<T> >::value</src> in future.
573  // AipsError is thrown if allocator is incompatible with the current allocator of the instance and changing allocator is prohibited,
574  // even if takeOverStorage == False.
575  // <group>
576  void replaceStorage(size_t n, T *&storagePointer, Bool takeOverStorage=True) {
577  replaceStorage(n, storagePointer, takeOverStorage, AllocSpec<NewDelAllocator<T> >::value);
578  }
579  template<typename Allocator>
580  void replaceStorage(size_t n, T *&storagePointer, Bool takeOverStorage, AllocSpec<Allocator> const &) {
581  if (keep_allocator_p && ! isCompatibleAllocator<Allocator>()) {
582  throw AipsError("Block::replaceStorage - Attemption to change allocator of Block");
583  }
584 
585  if (array && destroyPointer) {
586  traceFree (array, get_capacity());
587  allocator_p->destroy(array, get_size());
588  allocator_p->deallocate(array, get_capacity());
589  array = 0;
590  };
591  set_capacity(n);
592  set_size(n);
593  allocator_p = get_allocator<typename Allocator::type>();
594  array = storagePointer;
595  destroyPointer = takeOverStorage;
596  if (destroyPointer) storagePointer = 0;
597  }
598  // </group>
599 
600  // Index into the block (0-based). If the preprocessor symbol
601  // <src>AIPS_ARRAY_INDEX_CHECK</src> is defined, index checking will be done
602  // and an out-of-bounds index will cause an <src>indexError<uInt></src> to be
603  // thrown. Note that valid indices range between 0 and <src>nelements()-1</src>.
604  // <thrown>
605  // <li> indexError
606  // </thrown>
607  // <group>
608  T &operator[](size_t index) {
609 #if defined(AIPS_ARRAY_INDEX_CHECK)
610  // Write it this way to avoid casts; remember index and get_size() are
611  // unsigned.
612  if ((get_size() == 0) || (index > get_size() - 1)) {
613  throw(indexError<uInt>(index, "Block::operator[] - "
614  "index out of range"));
615  };
616 #endif
617  return array[index];
618  }
619  const T &operator[](size_t index) const {
620 #if defined(AIPS_ARRAY_INDEX_CHECK)
621  if ((get_size() == 0) || (index > get_size() - 1)) {
622  throw(indexError<uInt>(index, "Block::operator[] const - "
623  "index out of range"));
624  };
625 #endif
626  return array[index];
627  }
628  // </group>
629 
630  // Set all values in the block to "val".
631  // <group>
632  Block<T> &operator=(const T &val)
633  { T tmp=val; objset(array, tmp, get_size()); return *this;}
634  void set(const T &val) { *this = val; }
635  // </group>
636 
637  // If you really, really, need a "raw" pointer to the beginning of the
638  // storage area this will give it to you. This may leave dangling pointers
639  // if the block is destructed or if the assignment operator or resize
640  // is used. Returns a null pointer if <src>nelements() == 0</src>.
641  // It is best to only use this if you completely control the extent and
642  // lifetime of the <src>Block</src>.
643  // <h3> Examples of misuse </h3> <srcblock>
644  // Block<Int> *bp = new Block<Int>(100);
645  // Int *ip = bp->storage();
646  // DefaultAllocator<Int>::value.deallocate(bp, bp->capacity()); // Oops, ip is now dangling
647  // Block<Int> a(100),b(100);
648  // Int *ip = a.storage();
649  // a = b; // Likewise
650  // </srcblock>
651  // <group>
652  T *storage() {return array;}
653  const T *storage() const {return array;}
654  // </group>
655 
656  // The number of elements contained in this <src>Block<T></src>.
657  // <group>
658  size_t nelements() const {return size();}
659  size_t size() const {return get_capacity();}
660  // </group>
661 
662  // The capacity in this <src>Block<T></src>.
663  // <src>size() <= capacity()</src> is always true.
664  size_t capacity() const {return get_capacity();}
665 
666  // Is the block empty (i.e. no elements)?
667  Bool empty() const {return size() == 0;}
668 
669  // Define the STL-style iterators.
670  // It makes it possible to iterate through all data elements.
671  // <srcblock>
672  // Block<Int> bl(100,0);
673  // for (Block<Int>::iterator iter=bl.begin(); iter!=bl.end(); iter++) {
674  // *iter += 1;
675  // }
676  // </srcblock>
677  // <group name=STL-iterator>
678  // STL-style typedefs.
679  // <group>
680  typedef T value_type;
681  typedef T* iterator;
682  typedef const T* const_iterator;
683  typedef value_type* pointer;
684  typedef const value_type* const_pointer;
685  typedef value_type& reference;
686  typedef const value_type& const_reference;
687  typedef size_t size_type;
688  typedef ptrdiff_t difference_type;
689  // </group>
690  // Get the begin and end iterator object for this block.
691  // <group>
692  iterator begin()
693  { return array; }
694  const_iterator begin() const
695  { return array; }
696  iterator end()
697  { return array + size(); }
698  const_iterator end() const
699  { return array + size(); }
700  // </group>
701  // </group>
702 
703  inline void traceAlloc (const void* addr, size_t sz) const
704  {
705  if (itsTraceSize>0 && sz>=itsTraceSize) {
706  doTraceAlloc (addr, sz, whatType(static_cast<T*>(0)), sizeof(T));
707  }
708  }
709  inline void traceFree (const void* addr, size_t sz) const
710  {
711  if (itsTraceSize>0 && sz>=itsTraceSize) {
712  doTraceFree (addr, sz, whatType(static_cast<T*>(0)), sizeof(T));
713  }
714  }
715 
716  private:
717  friend class Array<T>; // to allow access to following constructors.
718 
719  Block(size_t n, ArrayInitPolicy initPolicy,
721  allocator_p(allocator), used_p(n), destroyPointer(
722  True), keep_allocator_p(False) {
723  init(initPolicy);
724  }
725  Block(size_t n, Allocator_private::AllocSpec<T> allocator) :
726  allocator_p(allocator.allocator), used_p(n), destroyPointer(
727  True), keep_allocator_p(False) {
728  init(init_anyway() ? ArrayInitPolicy::INIT : ArrayInitPolicy::NO_INIT);
729  }
730  Block(size_t n, T *&storagePointer, Bool takeOverStorage,
732  allocator_p(allocator), capacity_p(n), used_p(
733  n), array(storagePointer), destroyPointer(takeOverStorage), keep_allocator_p(
734  False) {
735  if (destroyPointer)
736  storagePointer = 0;
737  }
738  void construct(size_t pos, size_t n, T const *src) {
739  allocator_p->construct(&array[pos], n, src);
740  }
741  void construct(size_t pos, size_t n,
742  T const &initial_value) {
743  allocator_p->construct(&array[pos], n, initial_value);
744  }
745  void construct(size_t pos, size_type n) {
746  allocator_p->construct(&array[pos], n);
747  }
748  void destroy(size_t pos, size_type n) {
749  allocator_p->destroy(&array[pos], n);
750  }
752  return allocator_p;
753  }
754 
755  static bool init_anyway() {
758  }
759 
760  // end of friend
761 
762  void init(ArrayInitPolicy initPolicy) {
763  set_capacity(get_size());
764  if (get_capacity() > 0) {
765  array = allocator_p->allocate(get_capacity());
766  traceAlloc(array, get_capacity());
767  if (initPolicy == ArrayInitPolicy::INIT) {
768  try {
769  allocator_p->construct(array, get_size());
770  } catch (...) {
771  dealloc();
772  throw;
773  }
774  }
775  } else {
776  array = 0;
777  }
778  }
779 
780  void deinit() {
781  if (array && destroyPointer) {
782  allocator_p->destroy(array, get_size());
783  dealloc();
784  }
785  }
786  void dealloc() {
787  if (array && destroyPointer) {
788  traceFree(array, get_capacity());
789  allocator_p->deallocate(array, get_capacity());
790  array = 0;
791  }
792  }
793 
794  template<typename Allocator>
795  static typename Allocator_private::BulkAllocator<
796  typename Allocator::value_type> *get_allocator() {
798  Allocator>();
799  }
800 
801  template<typename Allocator>
804  typename Allocator::type::value_type> *other_allocator =
805  Allocator_private::get_allocator<typename Allocator::type>();
806  return other_allocator == allocator_p;
807  }
808 
809  // The number of used elements in the vector
810  size_t get_size() const { return used_p;}
811  // Set the number of used elements in the vector
812  void set_size(size_t new_value) {
813  AlwaysAssert(new_value <= get_capacity(), AipsError);
814  used_p = new_value;
815  }
816  // The capacity of the vector
817  size_t get_capacity() const { return capacity_p;}
818  // Set the capacity of the vector
819  void set_capacity(size_t new_value) {
820  capacity_p = new_value;
821  set_size(std::min(get_size(), capacity_p));
822  }
823 
824  // The allocator
826  // The capacity of the vector
827  size_t capacity_p;
828  // The number of used elements in the vector
829  size_t used_p;
830  // The actual storage
831  T *array;
832  // Can we delete the storage upon destruction?
834  // Can we change allocator or not?
836 };
837 
838 
839 // <summary>
840 // A drop-in replacement for <src>Block<T*></src>.
841 // </summary>
842 
843 // <use visibility=export>
844 // <prerequisite>
845 // <li> <linkto class=Block>Block</linkto>
846 // </prerequisite>
847 
848 // <synopsis>
849 // <src>PtrBlock<T*></src> has exactly the same interface as <src>Block<T*></src>
850 // and should be used in preference to the latter. It's purpose is solely to
851 // reduce the number of template instantiations.
852 // </synopsis>
853 
854 // <todo asof="1996/05/01">
855 // <li> Partial template specialization is another implementation choice that
856 // will be possible eventually.
857 // <li> It might be useful to have functions that know the template parameter
858 // is a pointer, e.g. that delete all the non-null pointers.
859 // </todo>
860 
861  template<class T> class PtrBlock {
862  public:
863  PtrBlock() : block_p() {}
864  explicit PtrBlock(size_t n) : block_p(n) {}
865  PtrBlock(size_t n, T val) : block_p(n, (void *)val) {}
866  PtrBlock(size_t n, T *&storagePointer, Bool takeOverStorage = True)
867  : block_p(n, (void **&)storagePointer, takeOverStorage) {}
868  PtrBlock(const PtrBlock<T> &other) : block_p(other.block_p) {}
870  { block_p = other.block_p; return *this;}
872  void resize(size_t n, Bool forceSmaller, Bool copyElements)
873  { block_p.resize(n,forceSmaller, copyElements); }
874  void resize(size_t n) {block_p.resize(n);}
875  void resize(size_t n, Bool forceSmaller) {block_p.resize(n, forceSmaller);}
876  void remove(size_t whichOne, Bool forceSmaller) {
877  block_p.remove(whichOne, forceSmaller);}
878  void remove(size_t whichOne) {block_p.remove(whichOne);}
879  void replaceStorage(size_t n, T *&storagePointer,
880  Bool takeOverStorage=True)
881  {block_p.replaceStorage(n, (void **&)storagePointer, takeOverStorage);}
882  T &operator[](size_t index) {return (T &)block_p[index];}
883  const T &operator[](size_t index) const {return (const T &)block_p[index];}
884  void set(const T &val) {block_p.set((void *const &)val);}
885  PtrBlock<T> &operator=(const T &val) {set(val); return *this;}
886  T *storage() {return (T *)block_p.storage();}
887  const T *storage() const {return (const T *)block_p.storage();}
888  size_t nelements() const {return block_p.nelements();}
889  size_t size() const {return block_p.size();}
890  Bool empty() const {return block_p.empty();}
891  private:
893  };
894 
895 
896 //# Instantiate extern templates for often used types.
897 #ifdef AIPS_CXX11
898  extern template class Block<Bool>;
899  extern template class Block<Char>;
900  extern template class Block<Short>;
901  extern template class Block<uShort>;
902  extern template class Block<Int>;
903  extern template class Block<uInt>;
904  extern template class Block<Int64>;
905  extern template class Block<Float>;
906  extern template class Block<Double>;
907  extern template class Block<Complex>;
908  extern template class Block<DComplex>;
909  extern template class Block<String>;
910  extern template class Block<void*>;
911 #endif
912 
913 
914 } //# NAMESPACE CASACORE - END
915 
916 #endif
Block(size_t n)
Create a Block with the given number of points.
Definition: Block.h:267
size_t size_type
Definition: Block.h:687
size_t size() const
Definition: Block.h:659
void prohibitChangingAllocator()
Prohibit changing allocator for this instance.
Definition: Block.h:554
void set_capacity(size_t new_value)
Set the capacity of the vector.
Definition: Block.h:819
Block(size_t n, T *&storagePointer, Bool takeOverStorage=True)
Create a Block from a C-array (i.e.
Definition: Block.h:341
const T * storage() const
Definition: Block.h:887
TableExprNode array(const TableExprNode &values, const TableExprNodeSet &shape)
Create an array of the given shape and fill it with the values.
Definition: ExprNode.h:1986
const T & operator[](size_t index) const
Definition: Block.h:619
static ArrayInitPolicy const NO_INIT
Don&#39;t initialize elements in the array.
Definition: Allocator.h:60
void construct(size_t pos, size_t n, T const *src)
Definition: Block.h:738
T value_type
Define the STL-style iterators.
Definition: Block.h:680
An aligned allocator with the default alignment.
Definition: Allocator.h:456
void resize(size_t n, Bool forceSmaller=False, Bool copyElements=True)
Resizes the Block.
Definition: Block.h:424
ptrdiff_t difference_type
Definition: Block.h:688
size_t nelements() const
The number of elements contained in this Block<T>.
Definition: Block.h:658
static bool init_anyway()
Definition: Block.h:755
const T * storage() const
Definition: Block.h:653
iterator end()
Definition: Block.h:696
const value_type & const_reference
Definition: Block.h:686
CASA_TMP_939727(void)
static void setTraceSize(size_t sz)
Set the trace size.
Index errors returning the bad index.
Definition: Error.h:320
Block(size_t n, Allocator_private::AllocSpec< T > allocator)
Definition: Block.h:725
size_t nelements() const
Definition: Block.h:888
A global enum used by some Array/Block constructors.
Definition: Allocator.h:57
void dealloc()
Definition: Block.h:786
const T & operator[](size_t index) const
Definition: Block.h:883
Block()
Create a zero-length Block.
Definition: Block.h:252
simple 1-D array
Definition: Block.h:111
void replaceStorage(size_t n, T *&storagePointer, Bool takeOverStorage=True)
Replace the internal storage with a C-array (i.e.
Definition: Block.h:576
size_t capacity() const
The capacity in this Block<T>.
Definition: Block.h:664
const value_type * const_pointer
Definition: Block.h:684
Bool empty() const
Definition: Block.h:890
PtrBlock(const PtrBlock< T > &other)
Definition: Block.h:868
size_t used_p
The number of used elements in the vector.
Definition: Block.h:829
T & operator[](size_t index)
Index into the block (0-based).
Definition: Block.h:608
void traceFree(const void *addr, size_t sz) const
Definition: Block.h:709
Block(size_t n, ArrayInitPolicy initPolicy, AllocSpec< Allocator > const &)
Create a Block with the given number of points.
Definition: Block.h:294
void replaceStorage(size_t n, T *&storagePointer, Bool takeOverStorage, AllocSpec< Allocator > const &)
Definition: Block.h:580
Bool keep_allocator_p
Can we change allocator or not?
Definition: Block.h:835
LatticeExprNode min(const LatticeExprNode &left, const LatticeExprNode &right)
PtrBlock(size_t n, T val)
Definition: Block.h:865
Allocator_private::BulkAllocator< T > * allocator_p
The allocator.
Definition: Block.h:825
const_iterator end() const
Definition: Block.h:698
static void doTraceAlloc(const void *addr, size_t nelem, DataType type, size_t sz)
Write alloc and free trace messages.
Bool empty() const
Is the block empty (i.e.
Definition: Block.h:667
static ArrayInitPolicy const INIT
Initialize all elements in the array with the default value.
Definition: Allocator.h:62
Block(size_t n, ArrayInitPolicy initPolicy, Allocator_private::BulkAllocator< T > *allocator)
Definition: Block.h:719
size_t size() const
Definition: Block.h:889
Block(size_t n, AllocSpec< Allocator > const &)
Create a Block with the given number of points.
Definition: Block.h:276
void resize(size_t n)
Definition: Block.h:874
T & operator[](size_t index)
Definition: Block.h:882
void permitChangingAllocator()
Permit changing allocator for this instance.
Definition: Block.h:558
void replaceStorage(size_t n, T *&storagePointer, Bool takeOverStorage=True)
Definition: Block.h:879
Block(size_t n, T *&storagePointer, Bool takeOverStorage, Allocator_private::BulkAllocator< T > *allocator)
Definition: Block.h:730
#define AlwaysAssert(expr, exception)
These marcos are provided for use instead of simply using the constructors of assert_ to allow additi...
Definition: Assert.h:157
bool Bool
Define the standard types used by Casacore.
Definition: aipstype.h:39
void set_size(size_t new_value)
Set the number of used elements in the vector.
Definition: Block.h:812
PtrBlock(size_t n)
Definition: Block.h:864
Allocator_private::BulkAllocator< T > * get_allocator()
Definition: Block.h:751
void resize(size_t n, Bool forceSmaller, Bool copyElements)
Definition: Block.h:872
PtrBlock< T > & operator=(const PtrBlock< T > &other)
Definition: Block.h:869
size_t get_capacity() const
The capacity of the vector.
Definition: Block.h:817
Bool isCompatibleAllocator()
Definition: Block.h:802
const Bool False
Definition: aipstype.h:41
A drop-in replacement for Block<T*>.
Definition: Block.h:861
iterator begin()
Get the begin and end iterator object for this block.
Definition: Block.h:692
value_type & reference
Definition: Block.h:685
template <class T, class U> class vector;
Definition: Array.h:169
void construct(size_t pos, size_t n, T const &initial_value)
Definition: Block.h:741
CASA_TMP_939727_int(int)
Block(size_t n, T const &val)
Create a Block of the given length, and initialize (via copy constructor for objects of type T) with ...
Definition: Block.h:304
simple 1-D array
Definition: ArrayIO.h:47
static size_t itsTraceSize
Definition: Block.h:125
PtrBlock(size_t n, T *&storagePointer, Bool takeOverStorage=True)
Definition: Block.h:866
Block(size_t n, ArrayInitPolicy initPolicy)
Create a Block with the given number of points.
Definition: Block.h:285
void init(ArrayInitPolicy initPolicy)
end of friend
Definition: Block.h:762
Base class for all Casacore library errors.
Definition: Error.h:135
const_iterator begin() const
Definition: Block.h:694
Block(AllocSpec< Allocator > const &)
Create a zero-length Block.
Definition: Block.h:259
void resize(size_t n, Bool forceSmaller, Bool copyElements, ArrayInitPolicy initPolicy)
Definition: Block.h:428
void construct(size_t pos, size_type n)
Definition: Block.h:745
Allocator specifier.
Definition: Allocator.h:472
static Allocator_private::BulkAllocator< typename Allocator::value_type > * get_allocator()
Definition: Block.h:796
Bool destroyPointer
Can we delete the storage upon destruction?
Definition: Block.h:833
void deinit()
Definition: Block.h:780
static BulkAllocator< typename Allocator::value_type > * get_allocator()
Definition: Allocator.h:349
Block< void * > block_p
Definition: Block.h:892
An allocator behaves like operator new[]/delete[].
Definition: Allocator.h:430
void traceAlloc(const void *addr, size_t sz) const
Definition: Block.h:703
size_t get_size() const
The number of used elements in the vector.
Definition: Block.h:810
Block< T > & operator=(const T &val)
Set all values in the block to "val".
Definition: Block.h:632
T * array
The actual storage.
Definition: Block.h:831
T * storage()
If you really, really, need a "raw" pointer to the beginning of the storage area this will give it to...
Definition: Block.h:652
Block(const Block< T > &other)
Copy the other block into this one.
Definition: Block.h:364
void destroy(size_t pos, size_type n)
Definition: Block.h:748
void resize(size_t n, Bool forceSmaller)
Definition: Block.h:875
~Block()
Frees up the storage pointed contained in the Block.
Definition: Block.h:396
PtrBlock< T > & operator=(const T &val)
Definition: Block.h:885
value_type * pointer
Definition: Block.h:683
const Bool True
Definition: aipstype.h:40
Block< T > & operator=(const Block< T > &other)
Assign other to this.
Definition: Block.h:381
this file contains all the compiler specific defines
Definition: mainpage.dox:28
size_t capacity_p
The capacity of the vector.
Definition: Block.h:827
LatticeExprNode value(const LatticeExprNode &expr)
This function returns the value of the expression without a mask.
const T * const_iterator
Definition: Block.h:682
Block(size_t n, T const &val, AllocSpec< Allocator > const &)
Create a Block of the given length, and initialize (via copy constructor for objects of type T) with ...
Definition: Block.h:319
static void doTraceFree(const void *addr, size_t nelem, DataType type, size_t sz)
Block(size_t n, T *&storagePointer, Bool takeOverStorage, AllocSpec< Allocator > const &)
Create a Block from a C-array (i.e.
Definition: Block.h:354
T * iterator
Definition: Block.h:681