#include <config.h>
#include <sarray/RangeImp.h>
#include <algorithm>
#include <stdexcept>
//#include <sstream>
using std::min;
using std::max;
using std::out_of_range;
using std::invalid_argument;
using std::logic_error;
//using std::ostringstream;
using std::string;
static Index makeDim(Index const &lower, Index const &upper, bool drop)
{
/*
Utility function for constructor: calculates the dimension of the
range with, or without, dropping of scalar dimensions.
*/
unsigned int ndim = upper.size();
if (!drop) {
//We only need to check this once
if (lower.size() != ndim) {
throw logic_error("RangeImp: Length mismatch in constructor");
}
else {
for (unsigned int i = 0; i < ndim; i++) {
if (upper[i] < lower[i]) {
throw out_of_range("RangeImp: upper < lower bound in constructor");
}
}
}
}
long *dim = new long[ndim];
int size = 0;
for (unsigned int i = 0; i < ndim; i++) {
long d = (upper[i] - lower[i] + 1);
if (!drop || d > 1) {
dim[size++] = d;
}
}
if (drop && size == 0) {
delete [] dim;
return Index(1); //FIXME: Why?
}
else {
Index index(size);
for (int j = 0; j < size; j++) {
index[j] = dim[j];
}
delete [] dim;
return index;
}
}
static unsigned long makeLength(Index const &lower, Index const &upper)
{
/*
Utility function for constructor: calculates the length of the
range.
*/
unsigned int ndim = upper.size();
if (ndim == 0) {
return 0;
}
else {
unsigned long length = 1;
for (unsigned int i = 0; i < ndim; i++) {
length *= (upper[i] - lower[i] + 1);
}
return length;
}
}
RangeImp::RangeImp(Index const &lower, Index const &upper)
: _lower(lower), _upper(upper),
_dim(makeDim(lower, upper, false)),
_dim_dropped(makeDim(lower, upper, true)),
_length(makeLength(lower, upper))
{
}
unsigned long RangeImp::length() const
{
return _length;
}
unsigned int RangeImp::ndim(bool drop) const
{
if (drop)
return _dim_dropped.size();
else
return _dim.size();
}
Index const &RangeImp::dim(bool drop) const
{
if (drop)
return _dim_dropped;
else
return _dim;
}
//debuggin
#include <iostream>
#include <sstream>
static string print(RangeImp const &range)
{
std::ostringstream ostr;
ostr << "[";
for (unsigned int i = 0; i < range.ndim(false); ++i) {
if (i > 0)
ostr << ",";
if (range.lower()[i] == range.upper()[i]) {
ostr << range.lower()[i];
}
else {
ostr << range.lower()[i] << ":" << range.upper()[i];
}
}
ostr << "]";
return ostr.str();
}
bool RangeImp::contains(RangeImp const &other) const
{
unsigned int ndim = _upper.size();
if (other._lower.size() != ndim) {
std::cout << print(*this) << " : " << print(other) << "\n";
throw invalid_argument("Range::contains. Dimension mismatch");
}
for (unsigned int i = 0; i < ndim; ++i) {
if (other._lower[i] < _lower[i] || other._upper[i] > _upper[i])
return false;
}
return true;
}
bool RangeImp::overlaps(RangeImp const &other) const
{
unsigned int dim = _upper.size();
if (other.ndim(false) != dim) {
throw invalid_argument("RangeImp::overlaps. Dimension mismatch");
}
for (unsigned int i = 0; i < dim; i++) {
if (max(_lower[i], other._lower[i]) > min(_upper[i], other._upper[i])) {
return false;
}
}
return true;
}
unsigned long RangeImp::leftOffset(Index const &index) const
{
if (!contains(RangeImp(index,index))) {
throw out_of_range("RangeImp::leftOffset. Index outside of allowed range");
}
unsigned long offset = 0;
long step = 1;
unsigned int ndim = _upper.size();
for (unsigned int i = 0; i < ndim; i++) {
offset += step * (index[i] - _lower[i]);
step *= (_upper[i] - _lower[i] + 1);
}
return offset;
}
Index RangeImp::leftIndex(unsigned long offset) const
{
if (offset >= _length) {
throw out_of_range("RangeImp::leftIndex. Offset exceeds length of range");
}
unsigned int ndim = _lower.size();
Index index(_lower);
for (unsigned int i = 0; i < ndim; ++i) {
index[i] += offset % _dim[i];
offset = offset / _dim[i];
}
return index;
}
unsigned long RangeImp::rightOffset(Index const &index) const
{
if (!contains(RangeImp(index,index))) {
throw out_of_range("RangeImp::rightOffset.Index outside of allowed range");
}
unsigned long offset = 0;
long step = 1;
for (int i = _upper.size() - 1; i >= 0; --i) {
offset += step * (index[i] - _lower[i]);
step *= (_upper[i] - _lower[i] + 1);
}
return offset;
}
Index RangeImp::rightIndex(unsigned long offset) const
{
if (offset >= _length)
throw out_of_range("RangeImp::rightIndex. Offset exceeds length of range");
int ndim = _lower.size();
Index index(_lower);
for (int i = ndim - 1; i >= 0; --i) {
index[i] += offset % _dim[i];
offset = offset / _dim[i];
}
return index;
}
Index const & RangeImp::lower() const
{
return _lower;
}
Index const & RangeImp::upper() const
{
return _upper;
}
bool RangeImp::operator<(RangeImp const &rhs) const
{
if (_lower < rhs._lower)
return true;
else if (rhs._lower < _lower)
return false;
else
return _upper < rhs._upper;
}
syntax highlighted by Code2HTML, v. 0.9.1