GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
Array.h
Go to the documentation of this file.
1 // Template array classes
2 /*
3 
4 Copyright (C) 1993-2013 John W. Eaton
5 Copyright (C) 2008-2009 Jaroslav Hajek
6 Copyright (C) 2010 VZLU Prague
7 
8 This file is part of Octave.
9 
10 Octave is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by the
12 Free Software Foundation; either version 3 of the License, or (at your
13 option) any later version.
14 
15 Octave is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with Octave; see the file COPYING. If not, see
22 <http://www.gnu.org/licenses/>.
23 
24 */
25 
26 #if !defined (octave_Array_h)
27 #define octave_Array_h 1
28 
29 #include <cassert>
30 #include <cstddef>
31 
32 #include <algorithm>
33 #include <iosfwd>
34 
35 #include "dim-vector.h"
36 #include "idx-vector.h"
37 #include "lo-traits.h"
38 #include "lo-utils.h"
39 #include "oct-sort.h"
40 #include "quit.h"
41 #include "oct-mem.h"
42 #include "oct-refcount.h"
43 
44 // One dimensional array class. Handles the reference counting for
45 // all the derived classes.
46 
47 template <class T>
48 class
49 Array
50 {
51 protected:
52 
53  //--------------------------------------------------------------------
54  // The real representation of all arrays.
55  //--------------------------------------------------------------------
56 
57  class ArrayRep
58  {
59  public:
60 
61  T *data;
64 
66  : data (no_ctor_new<T> (l)), len (l), count (1)
67  {
68  copy_or_memcpy (l, d, data);
69  }
70 
71  template <class U>
73  : data (no_ctor_new<T> (l)), len (l), count (1)
74  {
75  std::copy (d, d+l, data);
76  }
77 
78  ArrayRep (void) : data (0), len (0), count (1) { }
79 
81  : data (no_ctor_new<T> (n)), len (n), count (1) { }
82 
83  explicit ArrayRep (octave_idx_type n, const T& val)
84  : data (no_ctor_new<T> (n)), len (n), count (1)
85  {
86  fill_or_memset (n, val, data);
87  }
88 
89  ArrayRep (const ArrayRep& a)
90  : data (no_ctor_new<T> (a.len)), len (a.len), count (1)
91  {
92  copy_or_memcpy (a.len, a.data, data);
93  }
94 
95  ~ArrayRep (void) { no_ctor_delete<T> (data); }
96 
97  octave_idx_type length (void) const { return len; }
98 
99  private:
100 
101  // No assignment!
102 
103  ArrayRep& operator = (const ArrayRep& a);
104  };
105 
106  //--------------------------------------------------------------------
107 
108 public:
109 
110  void make_unique (void)
111  {
112  if (rep->count > 1)
113  {
114  ArrayRep *r = new ArrayRep (slice_data, slice_len);
115 
116  if (--rep->count == 0)
117  delete rep;
118 
119  rep = r;
120  slice_data = rep->data;
121  }
122  }
123 
124  typedef T element_type;
125 
126  typedef typename ref_param<T>::type crefT;
127 
128  typedef bool (*compare_fcn_type) (typename ref_param<T>::type,
129  typename ref_param<T>::type);
130 
131 protected:
132 
134 
136 
137  // Rationale:
138  // slice_data is a pointer to rep->data, denoting together with slice_len the
139  // actual portion of the data referenced by this Array<T> object. This allows
140  // to make shallow copies not only of a whole array, but also of contiguous
141  // subranges. Every time rep is directly manipulated, slice_data and slice_len
142  // need to be properly updated.
143 
146 
147  // slice constructor
148  Array (const Array<T>& a, const dim_vector& dv,
150  : dimensions (dv), rep(a.rep), slice_data (a.slice_data+l), slice_len (u-l)
151  {
152  rep->count++;
153  dimensions.chop_trailing_singletons ();
154  }
155 
156 private:
157 
158  typename Array<T>::ArrayRep *nil_rep (void) const
159  {
160  // NR was originally allocated with new, but that does not seem
161  // to be necessary since it will never be deleted. So just use
162  // a static object instead.
163 
164  static typename Array<T>::ArrayRep nr;
165  return &nr;
166  }
167 
168 protected:
169 
170  // For jit support
171  Array (T *sdata, octave_idx_type slen, octave_idx_type *adims, void *arep)
172  : dimensions (adims),
173  rep (reinterpret_cast<typename Array<T>::ArrayRep *> (arep)),
174  slice_data (sdata), slice_len (slen) { }
175 
176 public:
177 
178  // Empty ctor (0x0).
179 
180  Array (void)
181  : dimensions (), rep (nil_rep ()), slice_data (rep->data),
182  slice_len (rep->len)
183  {
184  rep->count++;
185  }
186 
187  // Obsolete 1D ctor (there are no 1D arrays).
189  : dimensions (n, 1), rep (new typename Array<T>::ArrayRep (n)),
190  slice_data (rep->data), slice_len (rep->len)
191  { }
192 
193  // Obsolete initialized 1D ctor (there are no 1D arrays).
194  explicit Array (octave_idx_type n, const T& val) GCC_ATTR_DEPRECATED
195  : dimensions (n, 1), rep (new typename Array<T>::ArrayRep (n)),
196  slice_data (rep->data), slice_len (rep->len)
197  {
198  fill (val);
199  }
200 
201  // nD uninitialized ctor.
202  explicit Array (const dim_vector& dv)
203  : dimensions (dv),
204  rep (new typename Array<T>::ArrayRep (dv.safe_numel ())),
205  slice_data (rep->data), slice_len (rep->len)
206  {
207  dimensions.chop_trailing_singletons ();
208  }
209 
210  // nD initialized ctor.
211  explicit Array (const dim_vector& dv, const T& val)
212  : dimensions (dv),
213  rep (new typename Array<T>::ArrayRep (dv.safe_numel ())),
214  slice_data (rep->data), slice_len (rep->len)
215  {
216  fill (val);
217  dimensions.chop_trailing_singletons ();
218  }
219 
220  // Reshape constructor.
221  Array (const Array<T>& a, const dim_vector& dv);
222 
223  // Type conversion case.
224  template <class U>
225  Array (const Array<U>& a)
226  : dimensions (a.dims ()),
227  rep (new typename Array<T>::ArrayRep (a.data (), a.length ())),
228  slice_data (rep->data), slice_len (rep->len)
229  { }
230 
231  // No type conversion case.
232  Array (const Array<T>& a)
233  : dimensions (a.dimensions), rep (a.rep), slice_data (a.slice_data),
234  slice_len (a.slice_len)
235  {
236  rep->count++;
237  }
238 
239 public:
240 
241  virtual ~Array (void)
242  {
243  if (--rep->count == 0)
244  delete rep;
245  }
246 
247  Array<T>& operator = (const Array<T>& a)
248  {
249  if (this != &a)
250  {
251  if (--rep->count == 0)
252  delete rep;
253 
254  rep = a.rep;
255  rep->count++;
256 
257  dimensions = a.dimensions;
258  slice_data = a.slice_data;
259  slice_len = a.slice_len;
260  }
261 
262  return *this;
263  }
264 
265  void fill (const T& val);
266 
267  void clear (void);
268  void clear (const dim_vector& dv);
269 
271  { clear (dim_vector (r, c)); }
272 
273  octave_idx_type capacity (void) const { return slice_len; }
274  octave_idx_type length (void) const { return capacity (); }
275  octave_idx_type nelem (void) const { return capacity (); }
276  octave_idx_type numel (void) const { return nelem (); }
277 
278  octave_idx_type dim1 (void) const { return dimensions(0); }
279  octave_idx_type dim2 (void) const { return dimensions(1); }
280  octave_idx_type dim3 (void) const { return dimensions(2); }
281 
282  // Return the array as a column vector.
283  Array<T> as_column (void) const
284  {
285  Array<T> retval (*this);
286  if (dimensions.length () != 2 || dimensions(1) != 1)
287  retval.dimensions = dim_vector (numel (), 1);
288 
289  return retval;
290  }
291 
292  // Return the array as a row vector.
293  Array<T> as_row (void) const
294  {
295  Array<T> retval (*this);
296  if (dimensions.length () != 2 || dimensions(0) != 1)
297  retval.dimensions = dim_vector (1, numel ());
298 
299  return retval;
300  }
301 
302  // Return the array as a matrix.
303  Array<T> as_matrix (void) const
304  {
305  Array<T> retval (*this);
306  if (dimensions.length () != 2)
307  retval.dimensions = dimensions.redim (2);
308 
309  return retval;
310  }
311 
312  octave_idx_type rows (void) const { return dim1 (); }
313  octave_idx_type cols (void) const { return dim2 (); }
314  octave_idx_type columns (void) const { return dim2 (); }
315  octave_idx_type pages (void) const { return dim3 (); }
316 
317  size_t byte_size (void) const
318  { return static_cast<size_t> (numel ()) * sizeof (T); }
319 
320  // Return a const-reference so that dims ()(i) works efficiently.
321  const dim_vector& dims (void) const { return dimensions; }
322 
323  Array<T> squeeze (void) const;
324 
325  void chop_trailing_singletons (void) GCC_ATTR_DEPRECATED
326  { dimensions.chop_trailing_singletons (); }
327 
330  octave_idx_type k) const;
332 
333  octave_idx_type compute_index_unchecked (const Array<octave_idx_type>& ra_idx)
334  const
335  { return dimensions.compute_index (ra_idx.data (), ra_idx.length ()); }
336 
337  // No checking, even for multiple references, ever.
338 
339  T& xelem (octave_idx_type n) { return slice_data[n]; }
340  crefT xelem (octave_idx_type n) const { return slice_data[n]; }
341 
343  { return xelem (dim1 ()*j+i); }
344  crefT xelem (octave_idx_type i, octave_idx_type j) const
345  { return xelem (dim1 ()*j+i); }
346 
348  { return xelem (i, dim2 ()*k+j); }
349  crefT xelem (octave_idx_type i, octave_idx_type j, octave_idx_type k) const
350  { return xelem (i, dim2 ()*k+j); }
351 
352  T& xelem (const Array<octave_idx_type>& ra_idx)
353  { return xelem (compute_index_unchecked (ra_idx)); }
354 
355  crefT xelem (const Array<octave_idx_type>& ra_idx) const
356  { return xelem (compute_index_unchecked (ra_idx)); }
357 
358  // FIXME: would be nice to fix this so that we don't unnecessarily force
359  // a copy, but that is not so easy, and I see no clean way to do it.
360 
361  T& checkelem (octave_idx_type n);
362  T& checkelem (octave_idx_type i, octave_idx_type j);
363  T& checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k);
364  T& checkelem (const Array<octave_idx_type>& ra_idx);
365 
367  {
368  make_unique ();
369  return xelem (n);
370  }
371 
372  T& elem (octave_idx_type i, octave_idx_type j) { return elem (dim1 ()*j+i); }
373 
375  { return elem (i, dim2 ()*k+j); }
376 
377  T& elem (const Array<octave_idx_type>& ra_idx)
378  { return Array<T>::elem (compute_index_unchecked (ra_idx)); }
379 
380 #if defined (BOUNDS_CHECKING)
381  T& operator () (octave_idx_type n) { return checkelem (n); }
382  T& operator () (octave_idx_type i, octave_idx_type j)
383  { return checkelem (i, j); }
384  T& operator () (octave_idx_type i, octave_idx_type j, octave_idx_type k)
385  { return checkelem (i, j, k); }
386  T& operator () (const Array<octave_idx_type>& ra_idx)
387  { return checkelem (ra_idx); }
388 #else
389  T& operator () (octave_idx_type n) { return elem (n); }
390  T& operator () (octave_idx_type i, octave_idx_type j) { return elem (i, j); }
392  { return elem (i, j, k); }
393  T& operator () (const Array<octave_idx_type>& ra_idx)
394  { return elem (ra_idx); }
395 #endif
396 
397  crefT checkelem (octave_idx_type n) const;
398  crefT checkelem (octave_idx_type i, octave_idx_type j) const;
399  crefT checkelem (octave_idx_type i, octave_idx_type j,
400  octave_idx_type k) const;
401  crefT checkelem (const Array<octave_idx_type>& ra_idx) const;
402 
403  crefT elem (octave_idx_type n) const { return xelem (n); }
404 
406  { return xelem (i, j); }
407 
409  { return xelem (i, j, k); }
410 
411  crefT elem (const Array<octave_idx_type>& ra_idx) const
412  { return Array<T>::xelem (compute_index_unchecked (ra_idx)); }
413 
414 #if defined (BOUNDS_CHECKING)
415  crefT operator () (octave_idx_type n) const { return checkelem (n); }
416  crefT operator () (octave_idx_type i, octave_idx_type j) const
417  { return checkelem (i, j); }
418  crefT operator () (octave_idx_type i, octave_idx_type j,
419  octave_idx_type k) const
420  { return checkelem (i, j, k); }
421  crefT operator () (const Array<octave_idx_type>& ra_idx) const
422  { return checkelem (ra_idx); }
423 #else
424  crefT operator () (octave_idx_type n) const { return elem (n); }
425  crefT operator () (octave_idx_type i, octave_idx_type j) const
426  { return elem (i, j); }
427  crefT operator () (octave_idx_type i, octave_idx_type j,
428  octave_idx_type k) const
429  { return elem (i, j, k); }
430  crefT operator () (const Array<octave_idx_type>& ra_idx) const
431  { return elem (ra_idx); }
432 #endif
433 
434  // Fast extractors. All of these produce shallow copies.
435  // Warning: none of these do check bounds, unless BOUNDS_CHECKING is on!
436 
437  // Extract column: A(:,k+1).
438  Array<T> column (octave_idx_type k) const;
439  // Extract page: A(:,:,k+1).
440  Array<T> page (octave_idx_type k) const;
441 
442  // Extract a slice from this array as a column vector: A(:)(lo+1:up).
443  // Must be 0 <= lo && up <= numel. May be up < lo.
444  Array<T> linear_slice (octave_idx_type lo, octave_idx_type up) const;
445 
446  Array<T> reshape (octave_idx_type nr, octave_idx_type nc) const
447  { return Array<T> (*this, dim_vector (nr, nc)); }
448 
449  Array<T> reshape (const dim_vector& new_dims) const
450  { return Array<T> (*this, new_dims); }
451 
452  Array<T> permute (const Array<octave_idx_type>& vec, bool inv = false) const;
453  Array<T> ipermute (const Array<octave_idx_type>& vec) const
454  { return permute (vec, true); }
455 
456  bool is_square (void) const { return (dim1 () == dim2 ()); }
457 
458  bool is_empty (void) const { return numel () == 0; }
459 
460  bool is_vector (void) const { return dimensions.is_vector (); }
461 
462  Array<T> transpose (void) const;
463  Array<T> hermitian (T (*fcn) (const T&) = 0) const;
464 
465  const T *data (void) const { return slice_data; }
466 
467  const T *fortran_vec (void) const { return data (); }
468 
469  T *fortran_vec (void);
470 
471  bool is_shared (void) { return rep->count > 1; }
472 
473  int ndims (void) const { return dimensions.length (); }
474 
475  // Indexing without resizing.
476 
477  Array<T> index (const idx_vector& i) const;
478 
479  Array<T> index (const idx_vector& i, const idx_vector& j) const;
480 
481  Array<T> index (const Array<idx_vector>& ia) const;
482 
483  virtual T resize_fill_value (void) const;
484 
485  // Resizing (with fill).
486 
487  void resize1 (octave_idx_type n, const T& rfv);
488  void resize1 (octave_idx_type n) { resize1 (n, resize_fill_value ()); }
489 
490  void resize (octave_idx_type n) GCC_ATTR_DEPRECATED { resize1 (n); }
491 
492  void resize (octave_idx_type nr, octave_idx_type nc,
493  const T& rfv) GCC_ATTR_DEPRECATED
494  {
495  resize2 (nr, nc, rfv);
496  }
497 
499  {
500  resize2 (nr, nc, resize_fill_value ());
501  }
502 
503  void resize (const dim_vector& dv, const T& rfv);
504  void resize (const dim_vector& dv) { resize (dv, resize_fill_value ()); }
505 
506  // Indexing with possible resizing and fill
507  // FIXME: this is really a corner case, that should better be
508  // handled directly in liboctinterp.
509 
510  Array<T> index (const idx_vector& i, bool resize_ok, const T& rfv) const;
511  Array<T> index (const idx_vector& i, bool resize_ok) const
512  {
513  return index (i, resize_ok, resize_fill_value ());
514  }
515 
516  Array<T> index (const idx_vector& i, const idx_vector& j, bool resize_ok,
517  const T& rfv) const;
518  Array<T> index (const idx_vector& i, const idx_vector& j,
519  bool resize_ok) const
520  {
521  return index (i, j, resize_ok, resize_fill_value ());
522  }
523 
524  Array<T> index (const Array<idx_vector>& ia, bool resize_ok,
525  const T& rfv) const;
526  Array<T> index (const Array<idx_vector>& ia, bool resize_ok) const
527  {
528  return index (ia, resize_ok, resize_fill_value ());
529  }
530 
531  // Indexed assignment (always with resize & fill).
532 
533  void assign (const idx_vector& i, const Array<T>& rhs, const T& rfv);
534  void assign (const idx_vector& i, const Array<T>& rhs)
535  {
536  assign (i, rhs, resize_fill_value ());
537  }
538 
539  void assign (const idx_vector& i, const idx_vector& j, const Array<T>& rhs,
540  const T& rfv);
541  void assign (const idx_vector& i, const idx_vector& j, const Array<T>& rhs)
542  {
543  assign (i, j, rhs, resize_fill_value ());
544  }
545 
546  void assign (const Array<idx_vector>& ia, const Array<T>& rhs, const T& rfv);
547  void assign (const Array<idx_vector>& ia, const Array<T>& rhs)
548  {
549  assign (ia, rhs, resize_fill_value ());
550  }
551 
552  // Deleting elements.
553 
554  // A(I) = [] (with a single subscript)
555  void delete_elements (const idx_vector& i);
556 
557  // A(:,...,I,...,:) = [] (>= 2 subscripts, one of them is non-colon)
558  void delete_elements (int dim, const idx_vector& i);
559 
560  // Dispatcher to the above two.
561  void delete_elements (const Array<idx_vector>& ia);
562 
563  // Insert an array into another at a specified position.
564  // If size (a) is [d1 d2 ... dN] and idx is [i1 i2 ... iN],
565  // this method is equivalent to
566  // x(i1:i1+d1-1, i2:i2+d2-1, ... , iN:iN+dN-1) = a.
567  Array<T>& insert (const Array<T>& a, const Array<octave_idx_type>& idx);
568 
569  // This is just a special case for idx = [r c 0 ...]
570  Array<T>& insert (const Array<T>& a, octave_idx_type r, octave_idx_type c);
571 
572  void maybe_economize (void)
573  {
574  if (rep->count == 1 && slice_len != rep->len)
575  {
576  ArrayRep *new_rep = new ArrayRep (slice_data, slice_len);
577  delete rep;
578  rep = new_rep;
579  slice_data = rep->data;
580  }
581  }
582 
583  void print_info (std::ostream& os, const std::string& prefix) const;
584 
585  // Unsafe. This function exists to support the MEX interface.
586  // You should not use it anywhere else.
587  void *mex_get_data (void) const { return const_cast<T *> (data ()); }
588 
589  Array<T> sort (int dim = 0, sortmode mode = ASCENDING) const;
590  Array<T> sort (Array<octave_idx_type> &sidx, int dim = 0,
591  sortmode mode = ASCENDING) const;
592 
593  // Ordering is auto-detected or can be specified.
594  sortmode is_sorted (sortmode mode = UNSORTED) const;
595 
596  // Sort by rows returns only indices.
597  Array<octave_idx_type> sort_rows_idx (sortmode mode = ASCENDING) const;
598 
599  // Ordering is auto-detected or can be specified.
600  sortmode is_sorted_rows (sortmode mode = UNSORTED) const;
601 
602  // Do a binary lookup in a sorted array. Must not contain NaNs.
603  // Mode can be specified or is auto-detected by comparing 1st and last element.
604  octave_idx_type lookup (const T& value, sortmode mode = UNSORTED) const;
605 
606  // Ditto, but for an array of values, specializing on the case when values
607  // are sorted. NaNs get the value N.
608  Array<octave_idx_type> lookup (const Array<T>& values,
609  sortmode mode = UNSORTED) const;
610 
611  // Count nonzero elements.
612  octave_idx_type nnz (void) const;
613 
614  // Find indices of (at most n) nonzero elements. If n is specified, backward
615  // specifies search from backward.
617  bool backward = false) const;
618 
619  // Returns the n-th element in increasing order, using the same ordering as
620  // used for sort. n can either be a scalar index or a contiguous range.
621  Array<T> nth_element (const idx_vector& n, int dim = 0) const;
622 
623  Array<T> diag (octave_idx_type k = 0) const;
624 
625  Array<T> diag (octave_idx_type m, octave_idx_type n) const;
626 
627  // Concatenation along a specified (0-based) dimension, equivalent to cat().
628  // dim = -1 corresponds to dim = 0 and dim = -2 corresponds to dim = 1,
629  // but apply the looser matching rules of vertcat/horzcat.
630  static Array<T>
631  cat (int dim, octave_idx_type n, const Array<T> *array_list);
632 
633  template <class U, class F>
634  Array<U>
635  map (F fcn) const
636  {
637  octave_idx_type len = length ();
638 
639  const T *m = data ();
640 
641  Array<U> result (dims ());
642  U *p = result.fortran_vec ();
643 
644  octave_idx_type i;
645  for (i = 0; i < len - 3; i += 4)
646  {
647  octave_quit ();
648 
649  p[i] = fcn (m[i]);
650  p[i+1] = fcn (m[i+1]);
651  p[i+2] = fcn (m[i+2]);
652  p[i+3] = fcn (m[i+3]);
653  }
654 
655  octave_quit ();
656 
657  for (; i < len; i++)
658  p[i] = fcn (m[i]);
659 
660  return result;
661  }
662 
663  // Overloads for function references.
664  template <class U>
665  Array<U>
666  map (U (&fcn) (T)) const
667  { return map<U, U (&) (T)> (fcn); }
668 
669  template <class U>
670  Array<U>
671  map (U (&fcn) (const T&)) const
672  { return map<U, U (&) (const T&)> (fcn); }
673 
674  // Generic any/all test functionality with arbitrary predicate.
675  template <class F, bool zero>
676  bool test (F fcn) const
677  {
678  return any_all_test<F, T, zero> (fcn, data (), length ());
679  }
680 
681  // Simpler calls.
682  template <class F>
683  bool test_any (F fcn) const
684  { return test<F, false> (fcn); }
685 
686  template <class F>
687  bool test_all (F fcn) const
688  { return test<F, true> (fcn); }
689 
690  // Overloads for function references.
691  bool test_any (bool (&fcn) (T)) const
692  { return test<bool (&) (T), false> (fcn); }
693 
694  bool test_any (bool (&fcn) (const T&)) const
695  { return test<bool (&) (const T&), false> (fcn); }
696 
697  bool test_all (bool (&fcn) (T)) const
698  { return test<bool (&) (T), true> (fcn); }
699 
700  bool test_all (bool (&fcn) (const T&)) const
701  { return test<bool (&) (const T&), true> (fcn); }
702 
703  template <class U> friend class Array;
704 
705  // Returns true if this->dims () == dv, and if so, replaces this->dimensions
706  // by a shallow copy of dv. This is useful for maintaining several arrays with
707  // supposedly equal dimensions (e.g. structs in the interpreter).
708  bool optimize_dimensions (const dim_vector& dv);
709 
710  // WARNING: Only call these functions from jit
711 
712  int *jit_ref_count (void) { return rep->count.get (); }
713 
714  T *jit_slice_data (void) const { return slice_data; }
715 
716  octave_idx_type *jit_dimensions (void) const { return dimensions.to_jit (); }
717 
718  void *jit_array_rep (void) const { return rep; }
719 
720 private:
721 
722  void resize2 (octave_idx_type nr, octave_idx_type nc, const T& rfv);
724  {
725  resize2 (nr, nc, resize_fill_value ());
726  }
727 
728  static void instantiation_guard ();
729 };
730 
731 // This is a simple wrapper template that will subclass an Array<T> type or any
732 // later type derived from it and override the default non-const operator() to
733 // not check for the array's uniqueness. It is, however, the user's
734 // responsibility to ensure the array is actually unaliased whenever elements
735 // are accessed.
736 
737 template<class ArrayClass>
738 class NoAlias : public ArrayClass
739 {
740  typedef typename ArrayClass::element_type T;
741 public:
742  NoAlias () : ArrayClass () { }
743 
744  // FIXME: this would be simpler once C++0x is available
745  template <class X>
746  explicit NoAlias (X x) : ArrayClass (x) { }
747 
748  template <class X, class Y>
749  explicit NoAlias (X x, Y y) : ArrayClass (x, y) { }
750 
751  template <class X, class Y, class Z>
752  explicit NoAlias (X x, Y y, Z z) : ArrayClass (x, y, z) { }
753 
755  { return ArrayClass::xelem (n); }
757  { return ArrayClass::xelem (i, j); }
759  { return ArrayClass::xelem (i, j, k); }
761  { return ArrayClass::xelem (ra_idx); }
762 };
763 
764 template <class T>
765 std::ostream&
766 operator << (std::ostream& os, const Array<T>& a);
767 
768 #endif