idx-vector.h

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1993-2012 John W. Eaton
00004 Copyright (C) 2008-2009 Jaroslav Hajek
00005 Copyright (C) 2009 VZLU Prague
00006 
00007 This file is part of Octave.
00008 
00009 Octave is free software; you can redistribute it and/or modify it
00010 under the terms of the GNU General Public License as published by the
00011 Free Software Foundation; either version 3 of the License, or (at your
00012 option) any later version.
00013 
00014 Octave is distributed in the hope that it will be useful, but WITHOUT
00015 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00017 for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with Octave; see the file COPYING.  If not, see
00021 <http://www.gnu.org/licenses/>.
00022 
00023 */
00024 
00025 #if !defined (octave_idx_vector_h)
00026 #define octave_idx_vector_h 1
00027 
00028 #include <cassert>
00029 
00030 #include <algorithm>
00031 #include <iosfwd>
00032 #include <memory>
00033 
00034 #include "dim-vector.h"
00035 #include "oct-inttypes.h"
00036 #include "oct-alloc.h"
00037 #include "oct-mem.h"
00038 #include "oct-refcount.h"
00039 
00040 template<class T> class Array;
00041 template<class T> class Sparse;
00042 class Range;
00043 
00044 // Design rationale:
00045 // idx_vector is a reference-counting, polymorphic pointer, that can contain
00046 // 4 types of index objects: a magic colon, a range, a scalar, or an index vector.
00047 // Polymorphic methods for single element access are provided, as well as
00048 // templates implementing "early dispatch", i.e. hoisting the checks for index
00049 // type out of loops.
00050 
00051 class
00052 OCTAVE_API
00053 idx_vector
00054 {
00055 public:
00056 
00057   enum idx_class_type
00058     {
00059       class_invalid = -1,
00060       class_colon = 0,
00061       class_range,
00062       class_scalar,
00063       class_vector,
00064       class_mask
00065     };
00066 
00067   template<class T> friend class std::auto_ptr;
00068 
00069 private:
00070 
00071   class OCTAVE_API idx_base_rep
00072   {
00073   public:
00074     idx_base_rep (void) : count (1), err (false) { }
00075 
00076     virtual ~idx_base_rep (void) { }
00077 
00078     // Non-range-checking element query.
00079     virtual octave_idx_type xelem (octave_idx_type i) const = 0;
00080 
00081     // Range-checking element query.
00082     virtual octave_idx_type checkelem (octave_idx_type i) const = 0;
00083 
00084     // Length of the index vector.
00085     virtual octave_idx_type length (octave_idx_type n) const = 0;
00086 
00087     // The maximum index + 1. The actual dimension is passed in.
00088     virtual octave_idx_type extent (octave_idx_type n) const = 0;
00089 
00090     // Index class.
00091     virtual idx_class_type idx_class (void) const { return class_invalid; }
00092 
00093     // Sorts, maybe uniqifies, and returns a clone object pointer.
00094     virtual idx_base_rep *sort_uniq_clone (bool uniq = false) = 0;
00095     // Sorts, and returns a sorting permutation (aka Array::sort).
00096     virtual idx_base_rep *sort_idx (Array<octave_idx_type>&) = 0;
00097 
00098     // Checks whether the index is colon or a range equivalent to colon.
00099     virtual bool is_colon_equiv (octave_idx_type) const { return false; }
00100 
00101     // The original dimensions of this object (used when subscribing by matrices).
00102     virtual dim_vector orig_dimensions (void) const { return dim_vector (); }
00103 
00104     // i/o
00105     virtual std::ostream& print (std::ostream& os) const = 0;
00106 
00107     virtual Array<octave_idx_type> as_array (void);
00108 
00109     octave_refcount<int> count;
00110 
00111     bool err;
00112 
00113   private:
00114 
00115     // No copying!
00116     idx_base_rep (const idx_base_rep&);
00117     idx_base_rep& operator = (const idx_base_rep&);
00118   };
00119 
00120   // The magic colon index.
00121   class OCTAVE_API idx_colon_rep : public idx_base_rep
00122   {
00123   public:
00124     idx_colon_rep (void) { }
00125 
00126     idx_colon_rep (char c);
00127 
00128     octave_idx_type xelem (octave_idx_type i) const { return i; }
00129 
00130     octave_idx_type checkelem (octave_idx_type i) const;
00131 
00132     octave_idx_type length (octave_idx_type n) const { return n; }
00133 
00134     octave_idx_type extent (octave_idx_type n) const { return n; }
00135 
00136     idx_class_type idx_class (void) const { return class_colon; }
00137 
00138     idx_base_rep *sort_uniq_clone (bool = false)
00139       { count++; return this; }
00140 
00141     idx_base_rep *sort_idx (Array<octave_idx_type>&);
00142 
00143     bool is_colon_equiv (octave_idx_type) const { return true; }
00144 
00145     std::ostream& print (std::ostream& os) const;
00146 
00147   private:
00148 
00149     DECLARE_OCTAVE_ALLOCATOR
00150 
00151     // No copying!
00152     idx_colon_rep (const idx_colon_rep& idx);
00153     idx_colon_rep& operator = (const idx_colon_rep& idx);
00154   };
00155 
00156   // To distinguish the "direct" constructors that blindly trust the data.
00157   enum direct { DIRECT };
00158 
00159   // The integer range index.
00160   class OCTAVE_API idx_range_rep : public idx_base_rep
00161   {
00162   public:
00163     idx_range_rep (octave_idx_type _start, octave_idx_type _len,
00164                    octave_idx_type _step, direct)
00165       : idx_base_rep (), start(_start), len(_len), step(_step) { }
00166 
00167     idx_range_rep (void)
00168       : start(0), len(0), step(1) { }
00169 
00170     // Zero-based constructor.
00171     idx_range_rep (octave_idx_type _start, octave_idx_type _limit,
00172                    octave_idx_type _step);
00173 
00174     idx_range_rep (const Range&);
00175 
00176     octave_idx_type xelem (octave_idx_type i) const
00177       { return start + i * step; }
00178 
00179     octave_idx_type checkelem (octave_idx_type i) const;
00180 
00181     octave_idx_type length (octave_idx_type) const { return len; }
00182 
00183     octave_idx_type extent (octave_idx_type n) const
00184       { return len ? std::max (n, (start + 1 + (step < 0 ? 0 : step * (len - 1)))) : n; }
00185 
00186     idx_class_type idx_class (void) const { return class_range; }
00187 
00188     idx_base_rep *sort_uniq_clone (bool uniq = false);
00189 
00190     idx_base_rep *sort_idx (Array<octave_idx_type>&);
00191 
00192     bool is_colon_equiv (octave_idx_type n) const
00193       { return start == 0 && step == 1 && len == n; }
00194 
00195     dim_vector orig_dimensions (void) const
00196       { return dim_vector (1, len); }
00197 
00198     octave_idx_type get_start (void) const { return start; }
00199 
00200     octave_idx_type get_step (void) const { return step; }
00201 
00202     std::ostream& print (std::ostream& os) const;
00203 
00204     Range unconvert (void) const;
00205 
00206     Array<octave_idx_type> as_array (void);
00207 
00208   private:
00209 
00210     DECLARE_OCTAVE_ALLOCATOR
00211 
00212     // No copying!
00213     idx_range_rep (const idx_range_rep& idx);
00214     idx_range_rep& operator = (const idx_range_rep& idx);
00215 
00216     octave_idx_type start, len, step;
00217 
00218   };
00219 
00220   // The integer scalar index.
00221   class OCTAVE_API idx_scalar_rep : public idx_base_rep
00222   {
00223   public:
00224     idx_scalar_rep (octave_idx_type i, direct)
00225       : data (i) { }
00226 
00227     idx_scalar_rep (void)
00228       : data (0) { }
00229 
00230     // Zero-based constructor.
00231     idx_scalar_rep (octave_idx_type i);
00232 
00233     template <class T>
00234     idx_scalar_rep (T x);
00235 
00236     octave_idx_type xelem (octave_idx_type) const { return data; }
00237 
00238     octave_idx_type checkelem (octave_idx_type i) const;
00239 
00240     octave_idx_type length (octave_idx_type) const { return 1; }
00241 
00242     octave_idx_type extent (octave_idx_type n) const
00243       { return std::max (n, data + 1); }
00244 
00245     idx_class_type idx_class (void) const { return class_scalar; }
00246 
00247     idx_base_rep *sort_uniq_clone (bool = false)
00248       { count++; return this; }
00249 
00250     idx_base_rep *sort_idx (Array<octave_idx_type>&);
00251 
00252     bool is_colon_equiv (octave_idx_type n) const
00253       { return n == 1 && data == 0; }
00254 
00255     dim_vector orig_dimensions (void) const { return dim_vector (1, 1); }
00256 
00257     octave_idx_type get_data (void) const { return data; }
00258 
00259     std::ostream& print (std::ostream& os) const;
00260 
00261     double unconvert (void) const;
00262 
00263     Array<octave_idx_type> as_array (void);
00264 
00265   private:
00266 
00267     DECLARE_OCTAVE_ALLOCATOR
00268 
00269     // No copying!
00270     idx_scalar_rep (const idx_scalar_rep& idx);
00271     idx_scalar_rep& operator = (const idx_scalar_rep& idx);
00272 
00273     octave_idx_type data;
00274 
00275   };
00276 
00277   // The integer vector index.
00278   class OCTAVE_API idx_vector_rep : public idx_base_rep
00279   {
00280   public:
00281     // Direct constructor.
00282     idx_vector_rep (octave_idx_type *_data, octave_idx_type _len,
00283                     octave_idx_type _ext, const dim_vector& od, direct)
00284       : data (_data), len (_len), ext (_ext), aowner (0), orig_dims (od) { }
00285 
00286     idx_vector_rep (void)
00287       : data (0), len (0), ext (0), aowner (0), orig_dims ()
00288       { }
00289 
00290     // Zero-based constructor.
00291     idx_vector_rep (const Array<octave_idx_type>& inda);
00292 
00293     idx_vector_rep (const Array<octave_idx_type>& inda,
00294                     octave_idx_type _ext, direct);
00295 
00296     template <class T>
00297     idx_vector_rep (const Array<T>&);
00298 
00299     idx_vector_rep (bool);
00300 
00301     idx_vector_rep (const Array<bool>&, octave_idx_type = -1);
00302 
00303     idx_vector_rep (const Sparse<bool>&);
00304 
00305     ~idx_vector_rep (void);
00306 
00307     octave_idx_type xelem (octave_idx_type i) const { return data[i]; }
00308 
00309     octave_idx_type checkelem (octave_idx_type i) const;
00310 
00311     octave_idx_type length (octave_idx_type) const { return len; }
00312 
00313     octave_idx_type extent (octave_idx_type n) const
00314       { return std::max (n, ext); }
00315 
00316     idx_class_type idx_class (void) const { return class_vector; }
00317 
00318     idx_base_rep *sort_uniq_clone (bool uniq = false);
00319 
00320     idx_base_rep *sort_idx (Array<octave_idx_type>&);
00321 
00322     dim_vector orig_dimensions (void) const { return orig_dims; }
00323 
00324     const octave_idx_type *get_data (void) const { return data; }
00325 
00326     std::ostream& print (std::ostream& os) const;
00327 
00328     Array<double> unconvert (void) const;
00329 
00330     Array<octave_idx_type> as_array (void);
00331 
00332   private:
00333 
00334     DECLARE_OCTAVE_ALLOCATOR
00335 
00336     // No copying!
00337     idx_vector_rep (const idx_vector_rep& idx);
00338     idx_vector_rep& operator = (const idx_vector_rep& idx);
00339 
00340     const octave_idx_type *data;
00341     octave_idx_type len;
00342     octave_idx_type ext;
00343 
00344     // This is a trick to allow user-given zero-based arrays to be used
00345     // as indices without copying.  If the following pointer is nonzero,
00346     // we do not own the data, but rather have an Array<octave_idx_type>
00347     // object that provides us the data.  Note that we need a pointer
00348     // because we deferred the Array<T> declaration and we do not want
00349     // it yet to be defined.
00350 
00351     Array<octave_idx_type> *aowner;
00352 
00353     dim_vector orig_dims;
00354   };
00355 
00356   // The logical mask index.
00357   class OCTAVE_API idx_mask_rep : public idx_base_rep
00358   {
00359   public:
00360     // Direct constructor.
00361     idx_mask_rep (bool *_data, octave_idx_type _len,
00362                   octave_idx_type _ext, const dim_vector& od, direct)
00363       : data (_data), len (_len), ext (_ext), lsti (-1), lste (-1),
00364         aowner (0), orig_dims (od) { }
00365 
00366     idx_mask_rep (void)
00367       : data (0), len (0), ext (0), lsti (-1), lste (-1), aowner (0),
00368         orig_dims ()
00369       { }
00370 
00371     idx_mask_rep (bool);
00372 
00373     idx_mask_rep (const Array<bool>&, octave_idx_type = -1);
00374 
00375     ~idx_mask_rep (void);
00376 
00377     octave_idx_type xelem (octave_idx_type i) const;
00378 
00379     octave_idx_type checkelem (octave_idx_type i) const;
00380 
00381     octave_idx_type length (octave_idx_type) const { return len; }
00382 
00383     octave_idx_type extent (octave_idx_type n) const
00384       { return std::max (n, ext); }
00385 
00386     idx_class_type idx_class (void) const { return class_mask; }
00387 
00388     idx_base_rep *sort_uniq_clone (bool = false)
00389       { count++; return this; }
00390 
00391     idx_base_rep *sort_idx (Array<octave_idx_type>&);
00392 
00393     dim_vector orig_dimensions (void) const { return orig_dims; }
00394 
00395     bool is_colon_equiv (octave_idx_type n) const
00396       { return len == n && ext == n; }
00397 
00398     const bool *get_data (void) const { return data; }
00399 
00400     std::ostream& print (std::ostream& os) const;
00401 
00402     Array<bool> unconvert (void) const;
00403 
00404     Array<octave_idx_type> as_array (void);
00405 
00406   private:
00407 
00408     DECLARE_OCTAVE_ALLOCATOR
00409 
00410     // No copying!
00411     idx_mask_rep (const idx_mask_rep& idx);
00412     idx_mask_rep& operator = (const idx_mask_rep& idx);
00413 
00414     const bool *data;
00415     octave_idx_type len;
00416     octave_idx_type ext;
00417 
00418     // FIXME: I'm not sure if this is a good design. Maybe it would be
00419     // better to employ some sort of generalized iteration scheme.
00420     mutable octave_idx_type lsti;
00421     mutable octave_idx_type lste;
00422 
00423     // This is a trick to allow user-given mask arrays to be used as
00424     // indices without copying.  If the following pointer is nonzero, we
00425     // do not own the data, but rather have an Array<bool> object that
00426     // provides us the data.  Note that we need a pointer because we
00427     // deferred the Array<T> declaration and we do not want it yet to be
00428     // defined.
00429 
00430     Array<bool> *aowner;
00431 
00432     dim_vector orig_dims;
00433   };
00434 
00435   idx_vector (idx_base_rep *r) : rep (r) { }
00436 
00437   // The shared empty vector representation (for fast default
00438   // constructor).
00439   static idx_vector_rep *nil_rep (void)
00440     {
00441       static idx_vector_rep ivr;
00442       return &ivr;
00443     }
00444 
00445   // The shared empty vector representation with the error flag set.
00446   static idx_vector_rep *err_rep (void)
00447     {
00448       static idx_vector_rep ivr;
00449       ivr.err = true;
00450       return &ivr;
00451     }
00452 
00453   // If there was an error in constructing the rep, replace it with
00454   // empty vector for safety.
00455   void chkerr (void)
00456     {
00457       if (rep->err)
00458         {
00459           if (--rep->count == 0)
00460             delete rep;
00461           rep = err_rep ();
00462           rep->count++;
00463         }
00464     }
00465 
00466 public:
00467 
00468   // Fast empty constructor.
00469   idx_vector (void) : rep (nil_rep ()) { rep->count++; }
00470 
00471   // Zero-based constructors (for use from C++).
00472   idx_vector (octave_idx_type i) : rep (new idx_scalar_rep (i))
00473     { chkerr (); }
00474 
00475   idx_vector (octave_idx_type start, octave_idx_type limit,
00476               octave_idx_type step = 1)
00477     : rep (new idx_range_rep (start, limit, step))
00478     { chkerr (); }
00479 
00480   static idx_vector
00481     make_range (octave_idx_type start, octave_idx_type step,
00482                 octave_idx_type len)
00483     {
00484       return idx_vector (new idx_range_rep (start, len, step, DIRECT));
00485     }
00486 
00487   idx_vector (const Array<octave_idx_type>& inda)
00488     : rep (new idx_vector_rep (inda))
00489     { chkerr (); }
00490 
00491   // Directly pass extent, no checking.
00492   idx_vector (const Array<octave_idx_type>& inda, octave_idx_type ext)
00493     : rep (new idx_vector_rep (inda, ext, DIRECT))
00494     { }
00495 
00496   // Colon is best constructed by simply copying (or referencing) this member.
00497   static const idx_vector colon;
00498 
00499   // or passing ':' here
00500   idx_vector (char c) : rep (new idx_colon_rep (c)) { chkerr (); }
00501 
00502   // Conversion constructors (used by interpreter).
00503 
00504   template <class T>
00505   idx_vector (octave_int<T> x) : rep (new idx_scalar_rep (x)) { chkerr (); }
00506 
00507   idx_vector (double x) : rep (new idx_scalar_rep (x)) { chkerr (); }
00508 
00509   idx_vector (float x) : rep (new idx_scalar_rep (x)) { chkerr (); }
00510 
00511   // A scalar bool does not necessarily map to scalar index.
00512   idx_vector (bool x) : rep (new idx_mask_rep (x)) { chkerr (); }
00513 
00514   template <class T>
00515   idx_vector (const Array<octave_int<T> >& nda) : rep (new idx_vector_rep (nda))
00516     { chkerr (); }
00517 
00518   idx_vector (const Array<double>& nda) : rep (new idx_vector_rep (nda))
00519     { chkerr (); }
00520 
00521   idx_vector (const Array<float>& nda) : rep (new idx_vector_rep (nda))
00522     { chkerr (); }
00523 
00524   idx_vector (const Array<bool>& nda);
00525 
00526   idx_vector (const Range& r)
00527     : rep (new idx_range_rep (r))
00528     { chkerr (); }
00529 
00530   idx_vector (const Sparse<bool>& nda) : rep (new idx_vector_rep (nda))
00531     { chkerr (); }
00532 
00533   idx_vector (const idx_vector& a) : rep (a.rep) { rep->count++; }
00534 
00535   ~idx_vector (void)
00536     {
00537       if (--rep->count == 0)
00538         delete rep;
00539     }
00540 
00541   idx_vector& operator = (const idx_vector& a)
00542     {
00543       if (this != &a)
00544         {
00545           if (--rep->count == 0)
00546             delete rep;
00547 
00548           rep = a.rep;
00549           rep->count++;
00550         }
00551       return *this;
00552     }
00553 
00554   idx_class_type idx_class (void) const { return rep->idx_class (); }
00555 
00556   octave_idx_type length (octave_idx_type n = 0) const
00557     { return rep->length (n); }
00558 
00559   octave_idx_type extent (octave_idx_type n) const
00560     { return rep->extent (n); }
00561 
00562   octave_idx_type xelem (octave_idx_type n) const
00563     { return rep->xelem (n); }
00564 
00565   octave_idx_type checkelem (octave_idx_type n) const
00566     { return rep->checkelem (n); }
00567 
00568   octave_idx_type operator () (octave_idx_type n) const
00569     {
00570 #if defined (BOUNDS_CHECKING)
00571       return rep->checkelem (n);
00572 #else
00573       return rep->xelem (n);
00574 #endif
00575     }
00576 
00577   operator bool (void) const
00578     { return ! rep->err; }
00579 
00580   bool is_colon (void) const
00581     { return rep->idx_class () == class_colon; }
00582 
00583   bool is_scalar (void) const
00584     { return rep->idx_class () == class_scalar; }
00585 
00586   bool is_range (void) const
00587     { return rep->idx_class () == class_range; }
00588 
00589   bool is_colon_equiv (octave_idx_type n) const
00590     { return rep->is_colon_equiv (n); }
00591 
00592   idx_vector sorted (bool uniq = false) const
00593     { return idx_vector (rep->sort_uniq_clone (uniq)); }
00594 
00595   idx_vector sorted (Array<octave_idx_type>& sidx) const
00596     { return idx_vector (rep->sort_idx (sidx)); }
00597 
00598   dim_vector orig_dimensions (void) const { return rep->orig_dimensions (); }
00599 
00600   octave_idx_type orig_rows (void) const
00601     { return orig_dimensions () (0); }
00602 
00603   octave_idx_type orig_columns (void) const
00604     { return orig_dimensions () (1); }
00605 
00606   int orig_empty (void) const
00607     { return (! is_colon () && orig_dimensions().any_zero ()); }
00608 
00609   // i/o
00610 
00611   std::ostream& print (std::ostream& os) const { return rep->print (os); }
00612 
00613   friend std::ostream& operator << (std::ostream& os, const idx_vector& a)
00614     { return a.print (os); }
00615 
00616   // Slice with specializations. No checking of bounds!
00617   //
00618   // This is equivalent to the following loop (but much faster):
00619   //
00620   // for (octave_idx_type i = 0; i < idx->length (n); i++)
00621   //   dest[i] = src[idx(i)];
00622   // return i;
00623   //
00624   template <class T>
00625   octave_idx_type
00626   index (const T *src, octave_idx_type n, T *dest) const
00627     {
00628       octave_idx_type len = rep->length (n);
00629 
00630       switch (rep->idx_class ())
00631         {
00632         case class_colon:
00633           copy_or_memcpy (len, src, dest);
00634           break;
00635 
00636         case class_range:
00637           {
00638             idx_range_rep * r = dynamic_cast<idx_range_rep *> (rep);
00639             octave_idx_type start = r->get_start (), step = r->get_step ();
00640             const T *ssrc = src + start;
00641             if (step == 1)
00642               copy_or_memcpy (len, ssrc, dest);
00643             else if (step == -1)
00644               std::reverse_copy (ssrc - len + 1, ssrc + 1, dest);
00645             else if (step == 0)
00646               std::fill_n (dest, len, *ssrc);
00647             else
00648               {
00649                 for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
00650                   dest[i] = ssrc[j];
00651               }
00652           }
00653           break;
00654 
00655         case class_scalar:
00656           {
00657             idx_scalar_rep * r = dynamic_cast<idx_scalar_rep *> (rep);
00658             dest[0] = src[r->get_data ()];
00659           }
00660           break;
00661 
00662         case class_vector:
00663           {
00664             idx_vector_rep * r = dynamic_cast<idx_vector_rep *> (rep);
00665             const octave_idx_type *data = r->get_data ();
00666             for (octave_idx_type i = 0; i < len; i++)
00667               dest[i] = src[data[i]];
00668           }
00669           break;
00670 
00671         case class_mask:
00672           {
00673             idx_mask_rep * r = dynamic_cast<idx_mask_rep *> (rep);
00674             const bool *data = r->get_data ();
00675             octave_idx_type ext = r->extent (0);
00676             for (octave_idx_type i = 0; i < ext; i++)
00677               if (data[i]) *dest++ = src[i];
00678           }
00679           break;
00680 
00681         default:
00682           assert (false);
00683           break;
00684         }
00685 
00686       return len;
00687     }
00688 
00689   // Slice assignment with specializations. No checking of bounds!
00690   //
00691   // This is equivalent to the following loop (but much faster):
00692   //
00693   // for (octave_idx_type i = 0; i < idx->length (n); i++)
00694   //   dest[idx(i)] = src[i];
00695   // return i;
00696   //
00697   template <class T>
00698   octave_idx_type
00699   assign (const T *src, octave_idx_type n, T *dest) const
00700     {
00701       octave_idx_type len = rep->length (n);
00702 
00703       switch (rep->idx_class ())
00704         {
00705         case class_colon:
00706           copy_or_memcpy (len, src, dest);
00707           break;
00708 
00709         case class_range:
00710           {
00711             idx_range_rep * r = dynamic_cast<idx_range_rep *> (rep);
00712             octave_idx_type start = r->get_start (), step = r->get_step ();
00713             T *sdest = dest + start;
00714             if (step == 1)
00715               copy_or_memcpy (len, src, sdest);
00716             else if (step == -1)
00717               std::reverse_copy (src, src + len, sdest - len + 1);
00718             else
00719               {
00720                 for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
00721                   sdest[j] = src[i];
00722               }
00723           }
00724           break;
00725 
00726         case class_scalar:
00727           {
00728             idx_scalar_rep * r = dynamic_cast<idx_scalar_rep *> (rep);
00729             dest[r->get_data ()] = src[0];
00730           }
00731           break;
00732 
00733         case class_vector:
00734           {
00735             idx_vector_rep * r = dynamic_cast<idx_vector_rep *> (rep);
00736             const octave_idx_type *data = r->get_data ();
00737             for (octave_idx_type i = 0; i < len; i++)
00738               dest[data[i]] = src[i];
00739           }
00740           break;
00741 
00742         case class_mask:
00743           {
00744             idx_mask_rep * r = dynamic_cast<idx_mask_rep *> (rep);
00745             const bool *data = r->get_data ();
00746             octave_idx_type ext = r->extent (0);
00747             for (octave_idx_type i = 0; i < ext; i++)
00748               if (data[i]) dest[i] = *src++;
00749           }
00750           break;
00751 
00752         default:
00753           assert (false);
00754           break;
00755         }
00756 
00757       return len;
00758     }
00759 
00760   // Slice fill with specializations. No checking of bounds!
00761   //
00762   // This is equivalent to the following loop (but much faster):
00763   //
00764   // for (octave_idx_type i = 0; i < idx->length (n); i++)
00765   //   dest[idx(i)] = val;
00766   // return i;
00767   //
00768   template <class T>
00769   octave_idx_type
00770   fill (const T& val, octave_idx_type n, T *dest) const
00771     {
00772       octave_idx_type len = rep->length (n);
00773 
00774       switch (rep->idx_class ())
00775         {
00776         case class_colon:
00777           std::fill (dest, dest + len, val);
00778           break;
00779 
00780         case class_range:
00781           {
00782             idx_range_rep * r = dynamic_cast<idx_range_rep *> (rep);
00783             octave_idx_type start = r->get_start (), step = r->get_step ();
00784             T *sdest = dest + start;
00785             if (step == 1)
00786               std::fill (sdest, sdest + len, val);
00787             else if (step == -1)
00788               std::fill (sdest - len + 1, sdest + 1, val);
00789             else
00790               {
00791                 for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
00792                   sdest[j] = val;
00793               }
00794           }
00795           break;
00796 
00797         case class_scalar:
00798           {
00799             idx_scalar_rep * r = dynamic_cast<idx_scalar_rep *> (rep);
00800             dest[r->get_data ()] = val;
00801           }
00802           break;
00803 
00804         case class_vector:
00805           {
00806             idx_vector_rep * r = dynamic_cast<idx_vector_rep *> (rep);
00807             const octave_idx_type *data = r->get_data ();
00808             for (octave_idx_type i = 0; i < len; i++)
00809               dest[data[i]] = val;
00810           }
00811           break;
00812 
00813         case class_mask:
00814           {
00815             idx_mask_rep * r = dynamic_cast<idx_mask_rep *> (rep);
00816             const bool *data = r->get_data ();
00817             octave_idx_type ext = r->extent (0);
00818             for (octave_idx_type i = 0; i < ext; i++)
00819               if (data[i]) dest[i] = val;
00820           }
00821           break;
00822 
00823         default:
00824           assert (false);
00825           break;
00826         }
00827 
00828       return len;
00829     }
00830 
00831   // Generic non-breakable indexed loop. The loop body should be
00832   // encapsulated in a single functor body.  This is equivalent to the
00833   // following loop (but faster, at least for simple inlined bodies):
00834   //
00835   // for (octave_idx_type i = 0; i < idx->length (n); i++) body (idx(i));
00836 
00837   template <class Functor>
00838   void
00839   loop (octave_idx_type n, Functor body) const
00840     {
00841       octave_idx_type len = rep->length (n);
00842 
00843       switch (rep->idx_class ())
00844         {
00845         case class_colon:
00846           for (octave_idx_type i = 0; i < len; i++) body (i);
00847           break;
00848 
00849         case class_range:
00850           {
00851             idx_range_rep * r = dynamic_cast<idx_range_rep *> (rep);
00852             octave_idx_type start = r->get_start (), step = r->get_step ();
00853             octave_idx_type i, j;
00854             if (step == 1)
00855               for (i = start, j = start + len; i < j; i++) body (i);
00856             else if (step == -1)
00857               for (i = start, j = start - len; i > j; i--) body (i);
00858             else
00859               for (i = 0, j = start; i < len; i++, j += step) body (j);
00860           }
00861           break;
00862 
00863         case class_scalar:
00864           {
00865             idx_scalar_rep * r = dynamic_cast<idx_scalar_rep *> (rep);
00866             body (r->get_data ());
00867           }
00868           break;
00869 
00870         case class_vector:
00871           {
00872             idx_vector_rep * r = dynamic_cast<idx_vector_rep *> (rep);
00873             const octave_idx_type *data = r->get_data ();
00874             for (octave_idx_type i = 0; i < len; i++) body (data[i]);
00875           }
00876           break;
00877 
00878         case class_mask:
00879           {
00880             idx_mask_rep * r = dynamic_cast<idx_mask_rep *> (rep);
00881             const bool *data = r->get_data ();
00882             octave_idx_type ext = r->extent (0);
00883             for (octave_idx_type i = 0; i < ext; i++)
00884               if (data[i]) body (i);
00885           }
00886           break;
00887 
00888         default:
00889           assert (false);
00890           break;
00891         }
00892 
00893     }
00894 
00895   // Generic breakable indexed loop. The loop body should be
00896   // encapsulated in a single functor body.  This is equivalent to the
00897   // following loop (but faster, at least for simple inlined bodies):
00898   //
00899   // for (octave_idx_type i = 0; i < idx->length (n); i++)
00900   //   if (body (idx(i))) break;
00901   // return i;
00902   //
00903 
00904   template <class Functor>
00905   octave_idx_type
00906   bloop (octave_idx_type n, Functor body) const
00907     {
00908       octave_idx_type len = rep->length (n), ret;
00909 
00910       switch (rep->idx_class ())
00911         {
00912         case class_colon:
00913           {
00914             octave_idx_type i;
00915             for (i = 0; i < len && body (i); i++) ;
00916             ret = i;
00917           }
00918           break;
00919 
00920         case class_range:
00921           {
00922             idx_range_rep * r = dynamic_cast<idx_range_rep *> (rep);
00923             octave_idx_type start = r->get_start (), step = r->get_step ();
00924             octave_idx_type i, j;
00925             if (step == 1)
00926               for (i = start, j = start + len; i < j && body (i); i++) ;
00927             else if (step == -1)
00928               for (i = start, j = start - len; i > j && body (i); i--) ;
00929             else
00930               for (i = 0, j = start; i < len && body (j); i++, j += step) ;
00931             ret = i;
00932           }
00933           break;
00934 
00935         case class_scalar:
00936           {
00937             idx_scalar_rep * r = dynamic_cast<idx_scalar_rep *> (rep);
00938             ret = body (r->get_data ()) ? 1 : 0;
00939           }
00940           break;
00941 
00942         case class_vector:
00943           {
00944             idx_vector_rep * r = dynamic_cast<idx_vector_rep *> (rep);
00945             const octave_idx_type *data = r->get_data ();
00946             octave_idx_type i;
00947             for (i = 0; i < len && body (data[i]); i++) ;
00948             ret = i;
00949           }
00950           break;
00951 
00952         case class_mask:
00953           {
00954             idx_mask_rep * r = dynamic_cast<idx_mask_rep *> (rep);
00955             const bool *data = r->get_data ();
00956             octave_idx_type ext = r->extent (0), j = 0;
00957             for (octave_idx_type i = 0; i < ext; i++)
00958               {
00959                 if (data[i])
00960                   {
00961                     if (body (i))
00962                       break;
00963                     else
00964                       j++;
00965                   }
00966               }
00967 
00968             ret = j;
00969           }
00970           break;
00971 
00972         default:
00973           assert (false);
00974           break;
00975         }
00976 
00977       return ret;
00978     }
00979 
00980   // Rationale:
00981   // This method is the key to "smart indexing". When indexing cartesian
00982   // arrays, sometimes consecutive index vectors can be reduced into a
00983   // single index.  If rows (A) = k and i.maybe_reduce (j) gives k, then
00984   // A(i,j)(:) is equal to A(k)(:).
00985 
00986   // If the next index can be reduced, returns true and updates this.
00987   bool maybe_reduce (octave_idx_type n, const idx_vector& j,
00988                      octave_idx_type nj);
00989 
00990   bool is_cont_range (octave_idx_type n,
00991                       octave_idx_type& l, octave_idx_type& u) const;
00992 
00993   // Returns the increment for ranges and colon, 0 for scalars and empty
00994   // vectors, 1st difference otherwise.
00995   octave_idx_type increment (void) const;
00996 
00997   idx_vector
00998   complement (octave_idx_type n) const;
00999 
01000   bool is_permutation (octave_idx_type n) const;
01001 
01002   // Returns the inverse permutation. If this is not a permutation on 1:n, the
01003   // result is undefined (but no error unless extent () != n).
01004   idx_vector inverse_permutation (octave_idx_type n) const;
01005 
01006   // Copies all the indices to a given array. Not allowed for colons.
01007   void copy_data (octave_idx_type *data) const;
01008 
01009   // If the index is a mask, convert it to index vector.
01010   idx_vector unmask (void) const;
01011 
01012   // Unconverts the index to a scalar, Range, double array or a mask.
01013   void unconvert (idx_class_type& iclass,
01014                   double& scalar, Range& range,
01015                   Array<double>& array, Array<bool>& mask) const;
01016 
01017   Array<octave_idx_type> as_array (void) const;
01018 
01019   // Raw pointer to index array.  This is non-const because it may be
01020   // necessary to mutate the index.
01021   const octave_idx_type *raw (void);
01022 
01023   bool is_vector (void) const;
01024 
01025   // FIXME -- these are here for compatibility.  They should be removed
01026   // when no longer in use.
01027 
01028   octave_idx_type elem (octave_idx_type n) const
01029     { return (*this) (n); }
01030 
01031   bool is_colon_equiv (octave_idx_type n, int) const
01032     { return is_colon_equiv (n); }
01033 
01034   octave_idx_type
01035   freeze (octave_idx_type z_len, const char *tag, bool resize_ok = false);
01036 
01037   void sort (bool uniq = false)
01038     { *this = sorted (uniq); }
01039 
01040   octave_idx_type ones_count (void) const;
01041 
01042   octave_idx_type max (void) const { return extent (1) - 1; }
01043 
01044 private:
01045 
01046   idx_base_rep *rep;
01047 
01048 };
01049 
01050 #endif
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines