#ifndef RANGE_H_
#define RANGE_H_

#include <sarray/Index.h>
#include <string>

class RangeImp;

/**
 * A Range object represents a range of indices used to take a subset
 * of a multi-dimensional array. For example, A[1:2,4,4:5] is a subset
 * of the array A defined by a range with lower boundary (1,4,4) and
 * upper boundary (2,4,5).
 *
 * All of the member functions of the Range class are constant, with
 * the exception of the assignment operator, so identical Range
 * objects (i.e. those with the same lower and upper bounds) can share
 * their memory.  In fact, the Range class is just a wrapper around
 * the RangeImp class, which actually implements the member functions.
 *
 * @short Range of indices 
 */
class Range {
  RangeImp const *_p;
 public:
  /**
   * Default constructor which constructs a NULL range, with zero-length
   * upper and lower limits.
   */
  Range();
  /**
   * Construct a range based on given lower and upper limits
   * A logic_error is thrown if these are of different lengths
   * @param lower lower limits. A range_error is thrown if any
   *              of these are < 1
   * @param upper upper limits. A range_error is thrown if any
   *              element of upper is smaller than the corresponding
   *              element of lower.
   * @exception logic_error range_error
   */
  Range(Index const &lower, Index const &upper);
  /**
   * Constructs a scalar range from an index. The upper and lower
   * bounds are both equal to the supplied index.  This constructor
   * is used for implicit conversion of Index to Range objects, so
   * that an Index can be supplied to any function in place of a 
   * Range parameter.
   */
  Range(Index const &index);
  /** Copy constructor */
  Range (Range const &rhs);
  /** Destructor */
  ~Range();
  /** Assignment operator */
  Range &operator=(Range const &rhs);
  /** Equality operator */
  bool operator==(Range const &range) const;
  /** Inequality operator */
  bool operator!=(Range const &range) const;
  /**
   * Length of the range. This is the number of indices that
   * are contained in the range.
   */
  unsigned long length() const;
  /**
   * Indicates whether the test range is completely contained inside this
   * range.
   *
   * @param range Test range, which must have the correct number of
   * dimensions, or an invalid_argument exception is thrown.  
   *
   * @exception invalid_argument
   */
  bool contains(Range const &range) const;
  /**
   * Returns the value of a RangeIterator after n iterations of nextLeft()
   * @see RangeIterator
   */
  Index leftIndex(long n) const;
  /**
   * The inverse of leftIndex. Returns the number of iterations of 
   * RangeIterator##nextLeft required to reach index.
   *
   * @param index Index to convert to offset. An out_of_range is thrown
   *              if the index is not contained in the range.
   * @see RangeIterator
   */
  long leftOffset(Index const &index) const;
  /**
   * Returns the value of a RangeIterator after n iterations of nextRight()
   * @see RangeIterator
   */
  Index rightIndex(long n) const;
  /**
   * The inverse of rightIndex. Returns the number of iterations of 
   * RangeIterator##nextRight required to reach index.
   *
   * @param index Index to convert to offset. An out_of_range is thrown
   *              if the index is not contained in the range.
   * @see RangeIterator
   */
  long rightOffset(Index const &index) const;
  /**
   * Dimension of the range. The range [1:4,2,3:5] has dimension
   * (4,1,3) if drop==false and (4,3) if drop==true. 
   *
   * @param drop Should dimensions of size 1 be dropped?
   */
  Index const &dim(bool drop) const;
  /**
   * Number of dimensions covered by the Range
   * @param drop Should dimensions of size 1 be dropped?
   */
  unsigned int ndim(bool drop) const;
  /**
   * lower limit of range
   */
  Index const & lower() const;
  /**
   * upper limit of range
   */
  Index const & upper() const;
  /**
   * Lexicographic ordering based on lower and then upper limit
   * @see Index##operator<
   */
  bool operator<(Range const &rhs) const;
};

/**
 * An test for NULL ranges.
 */
inline bool isNULL(Range const &range) { return range.length() == 0; }

/**
 * Returns a string containing a BUGS language representation of the
 * given range: e.g. a range with lower limit (1,2,3) and upper limit
 * (3,3,3) will be printed as "[1:3,2:3,3]"
 */
std::string print(Range const &range);

#endif /* RANGE_H_ */


syntax highlighted by Code2HTML, v. 0.9.1