dim-vector.h

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2003-2012 John W. Eaton
00004 Copyirght (C) 2009, 2010 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #if !defined (octave_dim_vector_h)
00025 #define octave_dim_vector_h 1
00026 
00027 #include <cassert>
00028 #include <limits>
00029 
00030 #include <sstream>
00031 #include <string>
00032 
00033 #include "lo-error.h"
00034 #include "lo-macros.h"
00035 #include "oct-refcount.h"
00036 
00037 // Rationale: This implementation is more tricky than Array, but the
00038 // big plus is that dim_vector requires only one allocation instead of
00039 // two.  It is (slightly) patterned after GCC's basic_string
00040 // implementation.  rep is a pointer to an array of memory, comprising
00041 // count, length, and the data:
00042 //
00043 //          <count>
00044 //          <ndims>
00045 //  rep --> <dims[0]>
00046 //          <dims[1]>
00047 //          ...
00048 //
00049 // The inlines count(), ndims() recover this data from the rep.  Note
00050 // that rep points to the beginning of dims to grant faster access
00051 // (reinterpret_cast is assumed to be an inexpensive operation).
00052 
00053 class
00054 OCTAVE_API
00055 dim_vector
00056 {
00057 private:
00058 
00059   octave_idx_type *rep;
00060 
00061   octave_idx_type& ndims (void) const { return rep[-1]; }
00062 
00063   octave_idx_type& count (void) const { return rep[-2]; }
00064 
00065   // Construct a new rep with count = 1 and ndims given.
00066 
00067   static octave_idx_type *newrep (int ndims)
00068   {
00069     octave_idx_type *r = new octave_idx_type[ndims + 2];
00070 
00071     *r++ = 1;
00072     *r++ = ndims;
00073 
00074     return r;
00075   }
00076 
00077   // Clone this->rep.
00078 
00079   octave_idx_type *clonerep (void)
00080   {
00081     int l = ndims ();
00082 
00083     octave_idx_type *r = new octave_idx_type[l + 2];
00084 
00085     *r++ = 1;
00086     *r++ = l;
00087 
00088     for (int i = 0; i < l; i++)
00089       r[i] = rep[i];
00090 
00091     return r;
00092   }
00093 
00094   // Clone and resize this->rep to length n, filling by given value.
00095 
00096   octave_idx_type *resizerep (int n, octave_idx_type fill_value)
00097   {
00098     int l = ndims ();
00099 
00100     if (n < 2)
00101       n = 2;
00102 
00103     octave_idx_type *r = new octave_idx_type[n + 2];
00104 
00105     *r++ = 1;
00106     *r++ = n;
00107 
00108     if (l > n)
00109       l = n;
00110 
00111     int j;
00112     for (j = 0; j < l; j++)
00113       r[j] = rep[j];
00114     for (; j < n; j++)
00115       r[j] = fill_value;
00116 
00117     return r;
00118   }
00119 
00120   // Free the rep.
00121 
00122   void freerep (void)
00123   {
00124     assert (count () == 0);
00125     delete [] (rep - 2);
00126   }
00127 
00128   void make_unique (void)
00129   {
00130     if (count () > 1)
00131       {
00132   octave_idx_type *new_rep = clonerep ();
00133 
00134   if (OCTREFCOUNT_ATOMIC_DECREMENT(&(count())) == 0)
00135     freerep ();
00136 
00137         rep = new_rep;
00138       }
00139   }
00140 
00141 public:
00142 
00143   // The constructor
00144   //
00145   //   dim_vector (n)
00146   //
00147   // creates an dimension vector with N rows and 1 column.  It is
00148   // deprecated because of the potentiol for confusion that it causes.
00149   // Additional constructors of the form
00150   //
00151   //   dim_vector (r, c)
00152   //   dim_vector (r, c, p)
00153   //   dim_vector (d1, d2, d3, d4, ...)
00154   //
00155   // are available for up to 7 dimensions.
00156 
00157   explicit dim_vector (octave_idx_type n) GCC_ATTR_DEPRECATED
00158     : rep (newrep (2))
00159   {
00160     rep[0] = n;
00161     rep[1] = 1;
00162   }
00163 
00164 #define ASSIGN_REP(i) rep[i] = d ## i;
00165 #define DIM_VECTOR_CTOR(N) \
00166   dim_vector (OCT_MAKE_DECL_LIST (octave_idx_type, d, N)) \
00167     : rep (newrep (N)) \
00168   { \
00169     OCT_ITERATE_MACRO (ASSIGN_REP, N) \
00170   }
00171 
00172   // Add more if needed.
00173   DIM_VECTOR_CTOR (2)
00174   DIM_VECTOR_CTOR (3)
00175   DIM_VECTOR_CTOR (4)
00176   DIM_VECTOR_CTOR (5)
00177   DIM_VECTOR_CTOR (6)
00178   DIM_VECTOR_CTOR (7)
00179 
00180 #undef ASSIGN_REP
00181 #undef DIM_VECTOR_CTOR
00182 
00183   octave_idx_type& elem (int i)
00184   {
00185 #ifdef BOUNDS_CHECKING
00186     assert (i >= 0 && i < ndims ());
00187 #endif
00188     make_unique ();
00189     return rep[i];
00190   }
00191 
00192   octave_idx_type elem (int i) const
00193   {
00194 #ifdef BOUNDS_CHECKING
00195     assert (i >= 0 && i < ndims ());
00196 #endif
00197     return rep[i];
00198   }
00199 
00200   void chop_trailing_singletons (void)
00201   {
00202     int l = ndims ();
00203     if (l > 2 && rep[l-1] == 1)
00204       {
00205         make_unique ();
00206         do
00207           l--;
00208         while (l > 2 && rep[l-1] == 1);
00209         ndims () = l;
00210       }
00211   }
00212 
00213   void chop_all_singletons (void);
00214 
00215 private:
00216 
00217   static octave_idx_type *nil_rep (void)
00218     {
00219       static dim_vector zv (0, 0);
00220       return zv.rep;
00221     }
00222 
00223   explicit dim_vector (octave_idx_type *r)
00224     : rep (r) { }
00225 
00226 public:
00227 
00228   static octave_idx_type dim_max (void);
00229 
00230   explicit dim_vector (void) : rep (nil_rep ())
00231   { OCTREFCOUNT_ATOMIC_INCREMENT (&(count())); }
00232 
00233   dim_vector (const dim_vector& dv) : rep (dv.rep)
00234   { OCTREFCOUNT_ATOMIC_INCREMENT (&(count())); }
00235 
00236   static dim_vector alloc (int n)
00237   {
00238     return dim_vector (newrep (n < 2 ? 2 : n));
00239   }
00240 
00241   dim_vector& operator = (const dim_vector& dv)
00242   {
00243     if (&dv != this)
00244       {
00245         if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0)
00246           freerep ();
00247 
00248         rep = dv.rep;
00249         OCTREFCOUNT_ATOMIC_INCREMENT (&(count()));
00250       }
00251 
00252     return *this;
00253   }
00254 
00255   ~dim_vector (void)
00256   {
00257     if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0)
00258       freerep ();
00259   }
00260 
00261   int length (void) const { return ndims (); }
00262 
00263   octave_idx_type& operator () (int i) { return elem (i); }
00264 
00265   octave_idx_type operator () (int i) const { return elem (i); }
00266 
00267   void resize (int n, int fill_value = 0)
00268   {
00269     int len = length ();
00270 
00271     if (n != len)
00272       {
00273         octave_idx_type *r = resizerep (n, fill_value);
00274 
00275         if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0)
00276           freerep ();
00277 
00278         rep = r;
00279       }
00280   }
00281 
00282   std::string str (char sep = 'x') const;
00283 
00284   bool all_zero (void) const
00285   {
00286     bool retval = true;
00287 
00288     for (int i = 0; i < length (); i++)
00289       {
00290         if (elem (i) != 0)
00291           {
00292             retval = false;
00293             break;
00294           }
00295       }
00296 
00297     return retval;
00298   }
00299 
00300   bool empty_2d (void) const
00301   {
00302     return length () == 2 && (elem (0) == 0 || elem (1) == 0);
00303   }
00304 
00305 
00306   bool zero_by_zero (void) const
00307   {
00308     return length () == 2 && elem (0) == 0 && elem (1) == 0;
00309   }
00310 
00311   bool any_zero (void) const
00312   {
00313     bool retval = false;
00314 
00315     for (int i = 0; i < length (); i++)
00316       {
00317         if (elem (i) == 0)
00318           {
00319             retval = true;
00320             break;
00321           }
00322       }
00323 
00324     return retval;
00325   }
00326 
00327   int num_ones (void) const;
00328 
00329   bool all_ones (void) const
00330   {
00331     return (num_ones () == length ());
00332   }
00333 
00334   // Return the number of elements that a matrix with this dimension
00335   // vector would have, NOT the number of dimensions (elements in the
00336   // dimension vector).
00337 
00338   octave_idx_type numel (int n = 0) const
00339   {
00340     int n_dims = length ();
00341 
00342     octave_idx_type retval = 1;
00343 
00344     for (int i = n; i < n_dims; i++)
00345       retval *= elem (i);
00346 
00347     return retval;
00348   }
00349 
00350   // The following function will throw a std::bad_alloc ()
00351   // exception if the requested size is larger than can be indexed by
00352   // octave_idx_type. This may be smaller than the actual amount of
00353   // memory that can be safely allocated on a system.  However, if we
00354   // don't fail here, we can end up with a mysterious crash inside a
00355   // function that is iterating over an array using octave_idx_type
00356   // indices.
00357 
00358   octave_idx_type safe_numel (void) const;
00359 
00360   bool any_neg (void) const
00361   {
00362     int n_dims = length ();
00363     int i;
00364 
00365     for (i = 0; i < n_dims; i++)
00366       if (elem (i) < 0)
00367         break;
00368 
00369     return i < n_dims;
00370   }
00371 
00372   dim_vector squeeze (void) const;
00373 
00374   // This corresponds to cat().
00375   bool concat (const dim_vector& dvb, int dim);
00376 
00377   // This corresponds to [,] (horzcat, dim = 0) and [;] (vertcat, dim = 1).
00378   // The rules are more relaxed here.
00379   bool hvcat (const dim_vector& dvb, int dim);
00380 
00381   // Force certain dimensionality, preserving numel ().  Missing
00382   // dimensions are set to 1, redundant are folded into the trailing
00383   // one.  If n = 1, the result is 2d and the second dim is 1
00384   // (dim_vectors are always at least 2D).
00385 
00386   dim_vector redim (int n) const;
00387 
00388   dim_vector as_column (void) const
00389     {
00390       if (length () == 2 && elem (1) == 1)
00391         return *this;
00392       else
00393         return dim_vector (numel (), 1);
00394     }
00395 
00396   dim_vector as_row (void) const
00397     {
00398       if (length () == 2 && elem (0) == 1)
00399         return *this;
00400       else
00401         return dim_vector (1, numel ());
00402     }
00403 
00404   bool is_vector (void) const
00405     {
00406       return (length () == 2 && (elem (0) == 1 || elem (1) == 1));
00407     }
00408 
00409   int first_non_singleton (int def = 0) const
00410     {
00411       for (int i = 0; i < length (); i++)
00412         {
00413           if (elem (i) != 1)
00414             return i;
00415         }
00416 
00417       return def;
00418     }
00419 
00420   // Compute a linear index from an index tuple.
00421 
00422   octave_idx_type compute_index (const octave_idx_type *idx) const
00423     {
00424       octave_idx_type k = 0;
00425       for (int i = length () - 1; i >= 0; i--)
00426         k = k * rep[i] + idx[i];
00427 
00428       return k;
00429     }
00430 
00431   // Ditto, but the tuple may be incomplete (nidx < length ()).
00432 
00433   octave_idx_type compute_index (const octave_idx_type *idx, int nidx) const
00434     {
00435       octave_idx_type k = 0;
00436       for (int i = nidx - 1; i >= 0; i--)
00437         k = k * rep[i] + idx[i];
00438 
00439       return k;
00440     }
00441 
00442   // Increment a multi-dimensional index tuple, optionally starting
00443   // from an offset position and return the index of the last index
00444   // position that was changed, or length () if just cycled over.
00445 
00446   int increment_index (octave_idx_type *idx, int start = 0) const
00447     {
00448       int i;
00449       for (i = start; i < length (); i++)
00450         {
00451           if (++(*idx) == rep[i])
00452             *idx++ = 0;
00453           else
00454             break;
00455         }
00456       return i;
00457     }
00458 
00459   // Return cumulative dimensions.
00460 
00461   dim_vector cumulative (void) const
00462     {
00463       int nd = length ();
00464       dim_vector retval = alloc (nd);
00465 
00466       octave_idx_type k = 1;
00467       for (int i = 0; i < nd; i++)
00468         retval.rep[i] = k *= rep[i];
00469 
00470       return retval;
00471     }
00472 
00473   // Compute a linear index from an index tuple.  Dimensions are
00474   // required to be cumulative.
00475 
00476   octave_idx_type cum_compute_index (const octave_idx_type *idx) const
00477     {
00478       octave_idx_type k = idx[0];
00479 
00480       for (int i = 1; i < length (); i++)
00481         k += rep[i-1] * idx[i];
00482 
00483       return k;
00484     }
00485 
00486 
00487   friend bool operator == (const dim_vector& a, const dim_vector& b);
00488 };
00489 
00490 inline bool
00491 operator == (const dim_vector& a, const dim_vector& b)
00492 {
00493   // Fast case.
00494   if (a.rep == b.rep)
00495     return true;
00496 
00497   bool retval = true;
00498 
00499   int a_len = a.length ();
00500   int b_len = b.length ();
00501 
00502   if (a_len != b_len)
00503     retval = false;
00504   else
00505     {
00506       for (int i = 0; i < a_len; i++)
00507         {
00508           if (a(i) != b(i))
00509             {
00510               retval = false;
00511               break;
00512             }
00513         }
00514     }
00515 
00516   return retval;
00517 }
00518 
00519 inline bool
00520 operator != (const dim_vector& a, const dim_vector& b)
00521 {
00522   return ! operator == (a, b);
00523 }
00524 
00525 #endif
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines