// -*-C++-*- 

// Copyright (C) 2004 
// Christian Stimming <stimming@tuhh.de>

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2, or (at
// your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public License along
// with this library; see the file COPYING.  If not, write to the Free
// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.

//      LAPACK++ (V. 1.1)
//      (C) 1992-1996 All Rights Reserved.

/** @file
 * @brief Matrix index class LaIndex
 */

#ifndef _LA_INDEX_H_
#define _LA_INDEX_H_

#include <iostream>
#include "arch.h"

/** @brief Matrix index class.
 *
 * This index class is used to adress submatrices of other matrices,
 * without actually copying any matrix elements in memory.
 *
 * Note that we name it "LaIndex" to avoid confusion with the
 * "index()" string function in C, or other generic Index()
 * functions.
 */
class DLLIMPORT LaIndex
{
   private:
      friend class LaGenMatDouble;
      friend class LaGenMatFloat;
      friend class LaGenMatInt;
      friend class LaGenMatLongInt;
      friend class LaGenMatComplex;
      int start_;
      int inc_;
      int end_;
   public:
      /** Construct a null index. Start, Increment, and End are
       * zero. null() will return true. 
       *
       * When used for addressing in one of the matrix classes, a
       * null index like this is equivalent to adressing "all
       * elements". To get the first row of a matrix \c A, you
       * could therefore write <tt>A( LaIndex(0), LaIndex()
       * )</tt>. This corresponds to the MATLAB notation of a
       * single <tt>:</tt> (colon).
       */
      inline LaIndex()
	 : start_(0)
	 , inc_(0)
	 , end_(0)
      {}
      
      /** Construct an index that points only to one element, specified
       * by the given argument.
       * 
       * Start and End is the given argument; Increment is unity but has
       * no effect. */
      inline LaIndex(int start) 
	 : start_(start)
	 , inc_(1)
	 , end_(start)
      {}

      /** Construct an index that points to a range of elements,
       * starting from the first argument and ending at the second
       * argument. The element at the starting index and the
       * element at the ending index are both included. This
       * corresponds to the MATLAB notation <tt>start:end</tt>.
       *
       * \a start and \a end are given by the two
       * arguments. Increment is unity. \a end has to be greater
       * or equal to \a start .*/
      LaIndex(int start, int end);

      /** Construct an index that points to a range of elements
       * with a given increment. The element at the starting index
       * is included; the element at the ending index is included
       * if its difference to the starting index is an integer
       * multiple of the increment.  This corresponds to the
       * MATLAB notation <tt>start:increment:end</tt>, but note
       * the different order of arguments in this constructor.
       *
       * The \a increment has to be nonzero. The \a end has to be
       * greater or equal to \a start if \a increment is
       * positive. If \a increment is negative, then \a end has to
       * be lesser or equal to \a start . Please watch out with
       * negative increments: The respective matrix functions may
       * or may not be correctly implemented for negative
       * increments. If in doubt, use only positive increments.
       *
       * Start, End, and Increment are given by the three
       * arguments. (We apologize for the confusing order of the
       * arguments.) */
      LaIndex(int start, int end, int increment);

      /** Copy constructor */
      inline LaIndex(const LaIndex &s)
	 : start_(s.start_)
	 , inc_(s.inc_)
	 , end_(s.end_)
      {}

   protected:
      // must have multply defined start(), inc() and end() member
      // functions for both const and non-const objects because
      // compiler complains in LaVector*.h, for example, about
      // assignment to const member.  (LaVector*.h line 112, 113,
      // 114) FIXME: Probably we should return by-value, not
      // by-reference!
      /** Returns the start index by-reference. That is, the index
       * of the first indexed element.
       *
       * DEPRECATED. Use the set() methods instead. */
      inline int& start() { return start_;}
      /** Returns the increment by-reference
       *
       * DEPRECATED. Use the set() methods instead.  */
      inline int& inc() { return inc_;}
      /** Returns the end index by-reference. That is, the index
       * of the last indexed element. (Not to be confused with the
       * index of the one-after-the-last element!)
       *
       * DEPRECATED. Use the set() methods instead.  */
      inline int& end() { return end_;}
   public:

      /** Returns the start index. That is, the index of the first
       * indexed element. */
      inline int start() const { return start_;}

      /** Returns the increment. It is guaranteed to be nonzero. */
      inline int inc() const { return inc_;}

      /** Returns the end index. That is, the index of the last
       * indexed element.
       *
       * (Not to be confused with the index of the
       * one-after-the-last element!) To be more precise, the
       * element at this ending index is being used if and only if
       * its difference to the starting index is an integer
       * multiple of the increment. */
      inline int end() const { return end_;}

      /** Returns the number of elements that are indexed by this
       * object. */
      inline int length() const { return ((end()-start())/inc() + 1);}

      /** Returns true if this is a null index which cannot be
       * used for indexing. */
      inline bool null() const { return (start() == 0 && 
					 inc() == 0 && end() == 0);}

   protected:
      /** DEPRECATED. Changes this index so that it points to a
       * range of elements, starting from the first argument and
       * ending at the second argument.
       *
       * Start and End are given by the two arguments. Increment
       * will be set to unity. 
       *
       * Deprecated. Use the set() method instead. Defining such
       * an operator() which is an assignment instead of a value
       * retrieval makes the indexing operations quite hard to
       * read.  Instead, use the set() method.
       */
      inline LaIndex& operator()(int start, int end){
	 start_=start; inc_=1; end_=end; return *this;}
   public:

      /** Changes this index so that it points to a range of
       * elements, starting from the first argument and ending at
       * the second argument. The element at the starting index
       * and the element at the ending index are both
       * included. This corresponds to the MATLAB notation
       * <tt>start:end</tt>.
       *
       * Start and End are given by the two arguments. Increment
       * will be set to unity. */
      inline LaIndex& set(int start, int end) {
	 start_=start; inc_=1; end_=end; return *this;}

      /** Changes this index so that it points to a range of
       * elements with a given increment. The element at the
       * starting index is included; the element at the ending
       * index is included if its difference to the starting index
       * is an integer multiple of the increment. The increment
       * argument has to be nonzero. This corresponds to the
       * MATLAB notation <tt>start:increment:end</tt>, but note
       * the different order of arguments in this constructor.
       *
       * The \a increment has to be nonzero. The \a end has to be
       * greater or equal to \a start if \a increment is
       * positive. If \a increment is negative, then \a end has to
       * be lesser or equal to \a start . Please watch out with
       * negative increments: The respective matrix functions may
       * or may not be correctly implemented for negative
       * increments. If in doubt, use only positive increments.
       *
       * Start, End, and Increment are given by the three
       * arguments. (We apologize for the confusing order of the
       * arguments, but this follows the three-valued
       * constructor.) */
      LaIndex& set(int start, int end, int increment);

      /** Shifts this index by the given argument. 
       *
       * The given argument is added to the Start and End
       * indices. Increment is unchanged.  */
      inline LaIndex& operator+(int i) {
	 start_+=i; end_+=i; return *this;}

      /** Copy assignment */
      inline LaIndex& operator=(const LaIndex& i) {
	 start_=i.start_; inc_=i.inc_; end_=i.end_; 
	 return *this;}

      /** Equality predicate */
      inline bool operator==(const LaIndex& s) {
	 return start_ == s.start_ && inc_ == s.inc_ && end_ == s.end_;
      }
      /** Inequality predicate. (New in lapackpp-2.4.5) */
      inline bool operator!=(const LaIndex& s) {
	 return !operator==(s);
      }
};

inline std::ostream& operator<<(std::ostream& s, const LaIndex& i)
{
    s << "(" << i.start() << ":" << i.inc() << ":" << i.end() << ")";

    return s;
}

#endif  
//  LA_INDEX_H_



syntax highlighted by Code2HTML, v. 0.9.1