Insert a comment with what the _defaultOf method for distributions would look like, if we were able to use type aliases in the manner shown.  When that change occurs, this method can be uncommented and the corresponding code in function resolution removed.

// Types.chpl
//
// Standard type routines.
//

//
// type predicates
//
proc chpl__isType(type t) param return true;
proc chpl__isType(e) param return false;

pragma "no instantiation limit"
proc _isPrimitiveType(type t) param return
  _isBooleanType(t)  ||
  _isIntegralType(t) ||
  _isRealType(t)     ||
//To allow imag, need to define casts from primitive types into imag.
//_isImagType(t)     ||
  (t == c_string);

pragma "no instantiation limit"
proc _isSimpleScalarType(type t) param return
  _isBooleanType(t) | _isIntegralType(t) | _isFloatType(t);

pragma "no instantiation limit"
proc _isBooleanType(type t) param return
  (t == bool) | (t == bool(8)) | (t == bool(16)) | (t == bool(32)) | (t == bool(64));

pragma "no instantiation limit"
proc _isIntegralType(type t) param return
  _isSignedType(t) || _isUnsignedType(t);

pragma "no instantiation limit"
proc _isSignedType(type t) param return
  (t == int(8)) || (t == int(16)) || (t == int(32)) || (t == int(64));

pragma "no instantiation limit"
proc _isUnsignedType(type t) param return
  (t == uint(8)) || (t == uint(16)) || (t == uint(32)) || (t == uint(64));

pragma "no instantiation limit"
proc _isEnumeratedType(type t) param {
  proc isEnum(type t: enumerated) param return true;
  proc isEnum(type t) param return false;
  return isEnum(t);
}

pragma "no instantiation limit"
proc _isComplexType(type t) param return
  (t == complex(64)) | (t == complex(128));

pragma "no instantiation limit"
proc _isFloatType(type t) param return
  (t == real(32)) | (t == real(64)) |
  (t == imag(32)) | (t == imag(64));

pragma "no instantiation limit"
proc _isRealType(type t) param return
  (t == real(32)) | (t == real(64));

pragma "no instantiation limit"
proc _isImagType(type t) param return
  (t == imag(32)) | (t == imag(64));

// Returns the unsigned equivalent of the input type.
proc chpl__unsignedType(type t) type
{
  if ! _isIntegralType(t) then
    compilerError("range idxType is non-integral: ", typeToString(t));

  return uint(numBits(t));
}

// Returns the signed equivalent of the input type.
proc chpl__signedType(type t) type
{
  if ! _isIntegralType(t) then
    compilerError("range idxType is non-integral: ", typeToString(t));

  return int(numBits(t));
}

proc chpl__maxIntTypeSameSign(type t) type {
  if ! _isIntegralType(t) then
    compilerError("type t is non-integral: ", typeToString(t));

  if (_isSignedType(t)) then
    return int(64);
  else
    return uint(64);
}

//
// These procedures indicate whether or not a type t is a specific type
//
proc isRangeType(type t) param where   t: range  return true;
proc isRangeType(type t) param where !(t: range) return false;

proc isDmapType(type t) param where   t: _distribution  return true;
proc isDmapType(type t) param where !(t: _distribution) return false;

proc isDomainType(type t) param where   t: _domain  return true;
proc isDomainType(type t) param where !(t: _domain) return false;

proc isArrayType(type t) param where   t: _array  return true;
proc isArrayType(type t) param where !(t: _array) return false;

// Is 'sub' a subtype (or equal to) 'super'?
proc isSubtype(type sub, type super) param where   sub: super  return true;
proc isSubtype(type sub, type super) param where !(sub: super) return false;

// Is 'sub' a proper subtype of 'super'?
proc isProperSubtype(type sub, type super) param
  where isSubtype(sub, super) && sub != super
  return true;
proc isProperSubtype(type sub, type super) param
  return false;

// What follows are the type _defaultOf methods, used to initialize types
// Booleans
inline proc _defaultOf(type t) param where (_isBooleanType(t)) return false:t;

// String
// defaultStringValue lives in runtime/include/chpl-string.h
// strings will be records, so param is not possible for them
inline proc _defaultOf(type t) where t: string return defaultStringValue;

// ints, reals, imags, complexes
inline proc _defaultOf(type t) param where (_isIntegralType(t)) return 0:t;
// TODO: In order to make _defaultOf param for reals and imags we had to split
// the cases into their default size and a non-param case.  It is hoped that
// in the future, floating point numbers may be castable whilst param.  In that
// world, we can again shrink these calls into the size-ignorant case.
inline proc _defaultOf(type t) param where t == real(64) return 0.0:t;
inline proc _defaultOf(type t) where (_isRealType(t) && t != real(64)) return 0.0:t;
inline proc _defaultOf(type t) param where t == imag(64) return 0.0i:t;
inline proc _defaultOf(type t) where (_isImagType(t) && t != imag(64)) return 0.0i:t;
// Also, complexes cannot yet be parametized
inline proc _defaultOf(type t): t where (_isComplexType(t)) {
  var ret:t = noinit;
  param floatwidth = numBits(t)/2;
  ret.re = 0.0:real(floatwidth);
  ret.im = 0.0:real(floatwidth);
  return ret;
}

// Enums
inline proc _defaultOf(type t) param where (_isEnumeratedType(t)) {
  return _enum_first(t);
}

// Classes
inline proc _defaultOf(type t) where (isClassType(t)) return nil:t;

// Various types whose default value is known
inline proc _defaultOf(type t) param where t: void return _void;
inline proc _defaultOf(type t) param where t: c_string return "":c_string;
inline proc _defaultOf(type t) where t: opaque return _nullOpaque;
inline proc _defaultOf(type t) where t: chpl_taskID_t return chpl_nullTaskID;
inline proc _defaultOf(type t) where t: _sync_aux_t return _nullSyncVarAuxFields;
inline proc _defaultOf(type t) where t: _single_aux_t return _nullSingleVarAuxFields;
inline proc _defaultOf(type t) where t: _task_list return _nullTaskList;

/* Need new <alias>() for this to function
proc _defaultOf(type t) where t:_distribution {
  var ret: t = noinit;
  type valType = __primitive("query type field", t, "_valueType");
  var typeInstance = new <valType>();
  ret = chpl__buildDistValue(typeInstance);
  return ret;
}
*/

// Returns true if it is legal to coerce t1 to t2, false otherwise.
proc chpl__legalIntCoerce(type t1, type t2) param
{
  if (_isSignedType(t2)) {
    if (_isSignedType(t1)) {
      return (numBits(t1) <= numBits(t2));
    } else {
      return (numBits(t1) < numBits(t2));
    }
  } else {
    if (_isSignedType(t1)) {
      return false;
    } else {
      return (numBits(t1) <= numBits(t2));
    }
  }
}

// Returns the type with which both s and t are compatible
// That is, both s and t can be coerced to the returned type.
proc chpl__commonType(type s, type t) type
{
  if ! _isIntegralType(s) then
    compilerError("Type ", typeToString(s) , " is non-integral: ");
  if ! _isIntegralType(t) then
    compilerError("Type ", typeToString(t) , " is non-integral: ");

  if numBits(s) > numBits(t) then return s;
  if numBits(s) < numBits(t) then return t;

  if _isSignedType(s) && ! _isSignedType(t) ||
     _isSignedType(t) && ! _isSignedType(s) then
    compilerError("Types ", typeToString(s) , " and ", typeToString(t), " are incompatible.");

  return s;
}

//
// numBits(type) -- returns the number of bits in a type
//

proc numBits(type t) param where t == bool {
  compilerError("default-width 'bool' does not have a well-defined size");
}
proc numBits(type t) param where t == bool(8) return 8;
proc numBits(type t) param where t == bool(16) return 16;
proc numBits(type t) param where t == bool(32) return 32;
proc numBits(type t) param where t == bool(64) return 64;
proc numBits(type t) param where t == int(8) return 8;
proc numBits(type t) param where t == int(16) return 16;
proc numBits(type t) param where t == int(32) return 32;
proc numBits(type t) param where t == int(64) return 64;
proc numBits(type t) param where t == uint(8) return 8;
proc numBits(type t) param where t == uint(16) return 16;
proc numBits(type t) param where t == uint(32) return 32;
proc numBits(type t) param where t == uint(64) return 64;
proc numBits(type t) param where t == real(32) return 32;
proc numBits(type t) param where t == real(64) return 64;
proc numBits(type t) param where t == imag(32) return 32;
proc numBits(type t) param where t == imag(64) return 64;
proc numBits(type t) param where t == complex(64) return 64;
proc numBits(type t) param where t == complex(128) return 128;

//
// numBytes(type) -- returns the number of bytes in a type
//

param bitsPerByte = 8;

proc numBytes(type t) param return numBits(t)/8;

//
// min(type) -- returns the minimum value a type can store
//

proc min(type t) where t == bool
  return false;

proc min(type t) where _isIntegralType(t) || _isFloatType(t)
  return __primitive( "_min", t);

proc min(type t) where _isComplexType(t) {
  var x: t;
  x.re = min(x.re.type);
  x.im = min(x.im.type);
  return x;
}

//
// max(type) -- returns the maximum value a type can store
//

proc max(type t) where t == bool
  return true;

proc max(type t) where _isIntegralType(t) || _isFloatType(t)
  return __primitive( "_max", t);

proc max(type t) where _isComplexType(t) {
  var x: t;
  x.re = max(x.re.type);
  x.im = max(x.im.type);
  return x;
}

iter chpl_enumerate(type t: enumerated) {
  const enumTuple = _enum_enumerate(t);
  for i in 1..enumTuple.size do
    yield enumTuple(i);
}

proc enum_minbits(type t: enumerated) param {
  return __primitive( "enum min bits", t);
}
proc enum_issigned(type t: enumerated) param {
  return __primitive( "enum is signed", t);
}
proc enum_mintype(type t: enumerated) type {
  param minbits = enum_minbits(t);
  param signed = enum_issigned(t);
  if signed {
    return int(minbits);
  } else {
    return uint(minbits);
  }
}

proc numBits(type t: enumerated) param {
  return numBits(enum_mintype(t));
}

//
// identity functions (for reductions)
//
inline proc _prod_id(type t) return 1:t;
inline proc _land_id(type t) return true;
inline proc _lor_id(type t) return false;
inline proc _lxor_id(type t) return false;
inline proc _band_id(type t) {
  // MPF - this doesn't really make sense for floating-point types,
  // but old code had it casting MAX_UINT to the same type...
  // I just moved it from the code generator since we don't need
  // a primitive to generate constants.
  if t == bool then return true;
  if t == int(8) then return -1:t;
  if t == int(16) then return -1:t;
  if t == int(32) then return -1:t;
  if t == int(64) then return -1:t;
  if t == real(32) then return max(uint(32)):t;
  if t == real(64) then return max(uint(64)):t;
  if t == imag(32) then return max(uint(32)):t;
  if t == imag(64) then return max(uint(64)):t;
  if t == complex(64) then return (max(uint(32)):real(32), max(uint(32)):real(32)):t;
  if t == complex(128) then return (max(uint(64)):real(64), max(uint(64)):real(64)):t;
  return max(t);
}
inline proc _bor_id(type t) return 0:t;
inline proc _bxor_id(type t) return 0:t;

// Types.chpl
//
// Standard type routines.
//

//
// type predicates
//
proc chpl__isType(type t) param return true;
proc chpl__isType(e) param return false;

pragma "no instantiation limit"
proc _isPrimitiveType(type t) param return
  _isBooleanType(t)  ||
  _isIntegralType(t) ||
  _isRealType(t)     ||
//To allow imag, need to define casts from primitive types into imag.
//_isImagType(t)     ||
  (t == c_string);

pragma "no instantiation limit"
proc _isSimpleScalarType(type t) param return
  _isBooleanType(t) | _isIntegralType(t) | _isFloatType(t);

pragma "no instantiation limit"
proc _isBooleanType(type t) param return
  (t == bool) | (t == bool(8)) | (t == bool(16)) | (t == bool(32)) | (t == bool(64));

pragma "no instantiation limit"
proc _isIntegralType(type t) param return
  _isSignedType(t) || _isUnsignedType(t);

pragma "no instantiation limit"
proc _isSignedType(type t) param return
  (t == int(8)) || (t == int(16)) || (t == int(32)) || (t == int(64));

pragma "no instantiation limit"
proc _isUnsignedType(type t) param return
  (t == uint(8)) || (t == uint(16)) || (t == uint(32)) || (t == uint(64));

pragma "no instantiation limit"
proc _isEnumeratedType(type t) param {
  proc isEnum(type t: enumerated) param return true;
  proc isEnum(type t) param return false;
  return isEnum(t);
}

pragma "no instantiation limit"
proc _isComplexType(type t) param return
  (t == complex(64)) | (t == complex(128));

pragma "no instantiation limit"
proc _isFloatType(type t) param return
  (t == real(32)) | (t == real(64)) |
  (t == imag(32)) | (t == imag(64));

pragma "no instantiation limit"
proc _isRealType(type t) param return
  (t == real(32)) | (t == real(64));

pragma "no instantiation limit"
proc _isImagType(type t) param return
  (t == imag(32)) | (t == imag(64));

// Returns the unsigned equivalent of the input type.
proc chpl__unsignedType(type t) type
{
  if ! _isIntegralType(t) then
    compilerError("range idxType is non-integral: ", typeToString(t));

  return uint(numBits(t));
}

// Returns the signed equivalent of the input type.
proc chpl__signedType(type t) type
{
  if ! _isIntegralType(t) then
    compilerError("range idxType is non-integral: ", typeToString(t));

  return int(numBits(t));
}

proc chpl__maxIntTypeSameSign(type t) type {
  if ! _isIntegralType(t) then
    compilerError("type t is non-integral: ", typeToString(t));

  if (_isSignedType(t)) then
    return int(64);
  else
    return uint(64);
}

//
// These procedures indicate whether or not a type t is a specific type
//
proc isRangeType(type t) param where   t: range  return true;
proc isRangeType(type t) param where !(t: range) return false;

proc isDmapType(type t) param where   t: _distribution  return true;
proc isDmapType(type t) param where !(t: _distribution) return false;

proc isDomainType(type t) param where   t: _domain  return true;
proc isDomainType(type t) param where !(t: _domain) return false;

proc isArrayType(type t) param where   t: _array  return true;
proc isArrayType(type t) param where !(t: _array) return false;

// Is 'sub' a subtype (or equal to) 'super'?
proc isSubtype(type sub, type super) param where   sub: super  return true;
proc isSubtype(type sub, type super) param where !(sub: super) return false;

// Is 'sub' a proper subtype of 'super'?
proc isProperSubtype(type sub, type super) param
  where isSubtype(sub, super) && sub != super
  return true;
proc isProperSubtype(type sub, type super) param
  return false;

// What follows are the type _defaultOf methods, used to initialize types
// Booleans
inline proc _defaultOf(type t) param where (_isBooleanType(t)) return false:t;

// String
// defaultStringValue lives in runtime/include/chpl-string.h
// strings will be records, so param is not possible for them
inline proc _defaultOf(type t) where t: string return defaultStringValue;

// ints, reals, imags, complexes
inline proc _defaultOf(type t) param where (_isIntegralType(t)) return 0:t;
// TODO: In order to make _defaultOf param for reals and imags we had to split
// the cases into their default size and a non-param case.  It is hoped that
// in the future, floating point numbers may be castable whilst param.  In that
// world, we can again shrink these calls into the size-ignorant case.
inline proc _defaultOf(type t) param where t == real(64) return 0.0:t;
inline proc _defaultOf(type t) where (_isRealType(t) && t != real(64)) return 0.0:t;
inline proc _defaultOf(type t) param where t == imag(64) return 0.0i:t;
inline proc _defaultOf(type t) where (_isImagType(t) && t != imag(64)) return 0.0i:t;
// Also, complexes cannot yet be parametized
inline proc _defaultOf(type t): t where (_isComplexType(t)) {
  var ret:t = noinit;
  param floatwidth = numBits(t)/2;
  ret.re = 0.0:real(floatwidth);
  ret.im = 0.0:real(floatwidth);
  return ret;
}

// Enums
inline proc _defaultOf(type t) param where (_isEnumeratedType(t)) {
  return _enum_first(t);
}

// Classes
inline proc _defaultOf(type t) where (isClassType(t)) return nil:t;

// Various types whose default value is known
inline proc _defaultOf(type t) param where t: void return _void;
inline proc _defaultOf(type t) param where t: c_string return "":c_string;
inline proc _defaultOf(type t) where t: opaque return _nullOpaque;
inline proc _defaultOf(type t) where t: chpl_taskID_t return chpl_nullTaskID;
inline proc _defaultOf(type t) where t: _sync_aux_t return _nullSyncVarAuxFields;
inline proc _defaultOf(type t) where t: _single_aux_t return _nullSingleVarAuxFields;
inline proc _defaultOf(type t) where t: _task_list return _nullTaskList;

// Returns true if it is legal to coerce t1 to t2, false otherwise.
proc chpl__legalIntCoerce(type t1, type t2) param
{
  if (_isSignedType(t2)) {
    if (_isSignedType(t1)) {
      return (numBits(t1) <= numBits(t2));
    } else {
      return (numBits(t1) < numBits(t2));
    }
  } else {
    if (_isSignedType(t1)) {
      return false;
    } else {
      return (numBits(t1) <= numBits(t2));
    }
  }
}

// Returns the type with which both s and t are compatible
// That is, both s and t can be coerced to the returned type.
proc chpl__commonType(type s, type t) type
{
  if ! _isIntegralType(s) then
    compilerError("Type ", typeToString(s) , " is non-integral: ");
  if ! _isIntegralType(t) then
    compilerError("Type ", typeToString(t) , " is non-integral: ");

  if numBits(s) > numBits(t) then return s;
  if numBits(s) < numBits(t) then return t;

  if _isSignedType(s) && ! _isSignedType(t) ||
     _isSignedType(t) && ! _isSignedType(s) then
    compilerError("Types ", typeToString(s) , " and ", typeToString(t), " are incompatible.");

  return s;
}

//
// numBits(type) -- returns the number of bits in a type
//

proc numBits(type t) param where t == bool {
  compilerError("default-width 'bool' does not have a well-defined size");
}
proc numBits(type t) param where t == bool(8) return 8;
proc numBits(type t) param where t == bool(16) return 16;
proc numBits(type t) param where t == bool(32) return 32;
proc numBits(type t) param where t == bool(64) return 64;
proc numBits(type t) param where t == int(8) return 8;
proc numBits(type t) param where t == int(16) return 16;
proc numBits(type t) param where t == int(32) return 32;
proc numBits(type t) param where t == int(64) return 64;
proc numBits(type t) param where t == uint(8) return 8;
proc numBits(type t) param where t == uint(16) return 16;
proc numBits(type t) param where t == uint(32) return 32;
proc numBits(type t) param where t == uint(64) return 64;
proc numBits(type t) param where t == real(32) return 32;
proc numBits(type t) param where t == real(64) return 64;
proc numBits(type t) param where t == imag(32) return 32;
proc numBits(type t) param where t == imag(64) return 64;
proc numBits(type t) param where t == complex(64) return 64;
proc numBits(type t) param where t == complex(128) return 128;

//
// numBytes(type) -- returns the number of bytes in a type
//

param bitsPerByte = 8;

proc numBytes(type t) param return numBits(t)/8;

//
// min(type) -- returns the minimum value a type can store
//

proc min(type t) where t == bool
  return false;

proc min(type t) where _isIntegralType(t) || _isFloatType(t)
  return __primitive( "_min", t);

proc min(type t) where _isComplexType(t) {
  var x: t;
  x.re = min(x.re.type);
  x.im = min(x.im.type);
  return x;
}

//
// max(type) -- returns the maximum value a type can store
//

proc max(type t) where t == bool
  return true;

proc max(type t) where _isIntegralType(t) || _isFloatType(t)
  return __primitive( "_max", t);

proc max(type t) where _isComplexType(t) {
  var x: t;
  x.re = max(x.re.type);
  x.im = max(x.im.type);
  return x;
}

iter chpl_enumerate(type t: enumerated) {
  const enumTuple = _enum_enumerate(t);
  for i in 1..enumTuple.size do
    yield enumTuple(i);
}

proc enum_minbits(type t: enumerated) param {
  return __primitive( "enum min bits", t);
}
proc enum_issigned(type t: enumerated) param {
  return __primitive( "enum is signed", t);
}
proc enum_mintype(type t: enumerated) type {
  param minbits = enum_minbits(t);
  param signed = enum_issigned(t);
  if signed {
    return int(minbits);
  } else {
    return uint(minbits);
  }
}

proc numBits(type t: enumerated) param {
  return numBits(enum_mintype(t));
}

//
// identity functions (for reductions)
//
inline proc _prod_id(type t) return 1:t;
inline proc _land_id(type t) return true;
inline proc _lor_id(type t) return false;
inline proc _lxor_id(type t) return false;
inline proc _band_id(type t) {
  // MPF - this doesn't really make sense for floating-point types,
  // but old code had it casting MAX_UINT to the same type...
  // I just moved it from the code generator since we don't need
  // a primitive to generate constants.
  if t == bool then return true;
  if t == int(8) then return -1:t;
  if t == int(16) then return -1:t;
  if t == int(32) then return -1:t;
  if t == int(64) then return -1:t;
  if t == real(32) then return max(uint(32)):t;
  if t == real(64) then return max(uint(64)):t;
  if t == imag(32) then return max(uint(32)):t;
  if t == imag(64) then return max(uint(64)):t;
  if t == complex(64) then return (max(uint(32)):real(32), max(uint(32)):real(32)):t;
  if t == complex(128) then return (max(uint(64)):real(64), max(uint(64)):real(64)):t;
  return max(t);
}
inline proc _bor_id(type t) return 0:t;
inline proc _bxor_id(type t) return 0:t;


Updating comments

Updating comments

config const debug = false;

use Sort;

//
// This module defines several iterators that are designed to help
// support reasoning about directory and file contents.  At present,
// all are serial.
//

//
// iter listdir(path: string, dotfiles=false, dirs=true, files=true, listlinks=true): string
//
//  listdir() lists the contents of a directory, similar to 'ls'
//    * path: the directory whose contents should be listed
//    * dotfiles: should files/directories that start with '.' be listed?
//    * dirs: should dirs be listed?
//    * files: should files be listed?
//    * listlinks: should symbolic links be listed?
//
// By default this routine lists all files and directories in the
// current directory, including symbolic links, as long as they don't
// start with '.'
//
iter listdir(path: string, dotfiles=false, dirs=true, files=true, listlinks=true): string {
  extern type DIRptr;
  extern type direntptr;
  extern proc opendir(name: c_string): DIRptr;
  extern proc readdir(dirp: DIRptr): direntptr;
  extern proc closedir(dirp: DIRptr): c_int;
  extern proc chpl_rt_isDir(pathname: c_string, followLinks: bool): c_int;

  proc direntptr.d_name(): c_string {
    extern proc chpl_rt_direntptr_getname(d: direntptr): c_string;

    return chpl_rt_direntptr_getname(this);
  }
  // End inlining

  var dir: DIRptr;
  var ent: direntptr;
  //  writeln("***Trying ", path);
  dir = opendir(path:c_string);
  if (!is_c_nil(dir)) {
    ent = readdir(dir);
    while (!is_c_nil(ent)) {
      const filename = ent.d_name();
      if (dotfiles || filename.substring(1) != '.') {
        if (filename != "." && filename != "..") {
          const fullpath = path + "/" + filename;
          if (chpl_rt_isDir(fullpath:c_string, listlinks)) {
            if (dirs) then
              yield filename;
          } else {
            if (files) then
              yield filename;
          }
        }
      }
      ent = readdir(dir);
    }
    closedir(dir);
  } else {
    extern proc perror(s: c_string);
    perror("error in listdir(): ");
  }
}

//
// iter walkdirs(path: string=".", topdown=true, depth=max(int), dotfiles=false,
//              followlinks=false, sort = false): string {
//
// walkdirs() recursively walks a directory structure, yielding directory names
//   * path: the directory to start from
//   * topdown: indicates whether to yield the directories using a preorder traversal
//   * depth: indicates the maximal depth of recursion to use
//   * dotfiles: indicates whether to enter directories with dotfile names
//   * followlinks: indicates whether to follow symbolic links or not
//   * sort: indicates whether to consider subdirectories in sorted order or not
//
// by default, walkdirs() will start in the current directory, process directories
// in preorder; recursively traverse subdirectories; and neither follow dotfile
// directories nor symbolic links.  It will not sort the directories by default.
//
iter walkdirs(path: string=".", topdown=true, depth=max(int), dotfiles=false,
              followlinks=false, sort = false): string {
  //  writeln("topdown = ", topdown);
  //  writeln("walkdirs() called with ", path, " depth=",depth);

  if (topdown) then
    yield path;

  if (depth) {
    var subdirs = listdir(path, dotfiles=dotfiles, files=false, listlinks=followlinks);
    if (sort) then
      QuickSort(subdirs);
    for subdir in subdirs {
      const fullpath = path + "/" + subdir;
      //      yield fullpath;
      //      writeln("Calling walkdirs with ", fullpath);
      for subdir in walkdirs(fullpath, topdown, depth-1, dotfiles, followlinks) do
        yield subdir;
    }
  }

  if (!topdown) then
    yield path;
}

//
// wordexp() gives a glob-like capability, implemented with C's wordexp()
// * pattern: the pattern to match against
//
// By default, it will list all files/directories in the directory
//
iter wordexp(pattern="*") {
  extern type wordexp_t;
  //  extern proc chpl_wordexp(pattern:c_string, flags:c_int, ref ret_glob:wordexp_t):c_int;
  extern proc wordexp(pattern:c_string, ref ret_glob: wordexp_t, flags_c_int): c_int;
  extern proc chpl_wordexp_num(x:wordexp_t): size_t;
  extern proc chpl_wordexp_index(x:wordexp_t, idx:size_t): c_string;
  extern proc wordfree(ref glb:wordexp_t);

  var glb : wordexp_t;

  const err = wordexp(pattern:c_string, glb, 0);

  for i in 0..chpl_wordexp_num(glb)-1 {
    yield chpl_wordexp_index(glb, i): string;
  }

  wordfree(glb);
}

//
// glob() gives glob() capabilities and is implemented using C's glob()
// * pattern: the pattern to match against
//
// By default, it will list all files/directories in the directory
//
iter glob(pattern="*") {
  extern type glob_t;
  //  extern proc chpl_glob(pattern:c_string, flags:c_int, ref ret_glob:glob_t):c_int;
  extern proc glob(pattern:c_string, flags: c_int, errfunc:c_void_ptr, ref ret_glob:glob_t):c_int;
  extern proc chpl_glob_num(x:glob_t): size_t;
  extern proc chpl_glob_index(x:glob_t, idx:size_t): c_string;
  extern proc globfree(ref glb:glob_t);

  var glb : glob_t;

  const err = glob(pattern:c_string, 0, c_nil, glb);

  for i in 0..chpl_glob_num(glb) - 1 do
    yield chpl_glob_index(glb, i): string;

  globfree(glb);
}

//
// findfiles() is a simple find-like utility implemented using the above routines
// * startdir: where to start when looking for files
// * recur: tells whether or not to descend recurisvely
// * dotfiles: tells whether or not to yield dotfiles
//
iter findfiles(startdir = ".", recur=false, dotfiles=false) {
  if (recur) then
    for subdir in walkdirs(startdir, dotfiles=dotfiles) do
      for file in listdir(subdir, dotfiles=dotfiles, dirs=false, files=true, listlinks=true) do
        yield subdir+"/"+file;
  else
    for file in listdir(startdir, dotfiles=dotfiles, dirs=false, files=true, listlinks=false) do
      yield startdir+"/"+file;
}

config const debug = false;

use Sort;

//
// This module defines several iterators that are designed to help
// support reasoning about directory and file contents.  At present,
// all are serial.
//

//
//  iter listdir(path: string, dotfiles=false, dirs=true, files=false): string
//
//  listdir() lists the contents of a directory, similar to 'ls'
//    * path: the directory to list
//    * dotfiles: should dotfiles be included?
//    * dirs: should dirs be listed?
//    * files: should files be listed?
//
// By default it lists all directories in the current directory as
// long as they don't start with '.'
//
iter listdir(path: string, dotfiles=false, dirs=true, files=true, listlinks=true): string {
  extern type DIRptr;
  extern type direntptr;
  extern proc opendir(name: c_string): DIRptr;
  extern proc readdir(dirp: DIRptr): direntptr;
  extern proc closedir(dirp: DIRptr): c_int;
  extern proc chpl_rt_isDir(pathname: c_string, followLinks: bool): c_int;

  proc direntptr.d_name(): c_string {
    extern proc chpl_rt_direntptr_getname(d: direntptr): c_string;

    return chpl_rt_direntptr_getname(this);
  }
  // End inlining

  var dir: DIRptr;
  var ent: direntptr;
  //  writeln("***Trying ", path);
  dir = opendir(path:c_string);
  if (!is_c_nil(dir)) {
    ent = readdir(dir);
    while (!is_c_nil(ent)) {
      const filename = ent.d_name();
      if (dotfiles || filename.substring(1) != '.') {
        if (filename != "." && filename != "..") {
          const fullpath = path + "/" + filename;
          if (chpl_rt_isDir(fullpath:c_string, listlinks)) {
            if (dirs) then
              yield filename;
          } else {
            if (files) then
              yield filename;
          }
        }
      }
      ent = readdir(dir);
    }
    closedir(dir);
  } else {
    extern proc perror(s: c_string);
    perror("error in listdir(): ");
  }
}

//
// iter walkdirs(path: string=".", topdown=true, depth=max(int), dotfiles=false,
//              followlinks=false, sort = false): string {
//
// walkdirs() recursively walks a directory structure, yielding directory names
//   * path: the directory to start from
//   * topdown: indicates whether to yield the directories using a preorder traversal
//   * depth: indicates the maximal depth of recursion to use
//   * dotfiles: indicates whether to enter directories with dotfile names
//   * followlinks: indicates whether to follow symbolic links or not
//   * sort: indicates whether to consider subdirectories in sorted order or not
//
iter walkdirs(path: string=".", topdown=true, depth=max(int), dotfiles=false,
              followlinks=false, sort = false): string {
  //  writeln("topdown = ", topdown);
  //  writeln("walkdirs() called with ", path, " depth=",depth);

  if (topdown) then
    yield path;

  if (depth) {
    var subdirs = listdir(path, dotfiles=dotfiles, files=false, listlinks=followlinks);
    if (sort) then
      QuickSort(subdirs);
    for subdir in subdirs {
      const fullpath = path + "/" + subdir;
      //      yield fullpath;
      //      writeln("Calling walkdirs with ", fullpath);
      for subdir in walkdirs(fullpath, topdown, depth-1, dotfiles, followlinks) do
        yield subdir;
    }
  }

  if (!topdown) then
    yield path;
}

//
// wordexp() gives a glob-like capability, implemented with C's wordexp()
// * pattern: the pattern to match against
//
iter wordexp(pattern="*") {
  extern type wordexp_t;
  //  extern proc chpl_wordexp(pattern:c_string, flags:c_int, ref ret_glob:wordexp_t):c_int;
  extern proc wordexp(pattern:c_string, ref ret_glob: wordexp_t, flags_c_int): c_int;
  extern proc chpl_wordexp_num(x:wordexp_t): size_t;
  extern proc chpl_wordexp_index(x:wordexp_t, idx:size_t): c_string;
  extern proc wordfree(ref glb:wordexp_t);

  var glb : wordexp_t;

  const err = wordexp(pattern:c_string, glb, 0);

  for i in 0..chpl_wordexp_num(glb)-1 {
    yield chpl_wordexp_index(glb, i): string;
  }

  wordfree(glb);
}

//
// glob() gives glob() capabilities and is implemented using C's glob()
// * pattern: the pattern to match against
//
iter glob(pattern="*") {
  extern type glob_t;
  //  extern proc chpl_glob(pattern:c_string, flags:c_int, ref ret_glob:glob_t):c_int;
  extern proc glob(pattern:c_string, flags: c_int, errfunc:c_void_ptr, ref ret_glob:glob_t):c_int;
  extern proc chpl_glob_num(x:glob_t): size_t;
  extern proc chpl_glob_index(x:glob_t, idx:size_t): c_string;
  extern proc globfree(ref glb:glob_t);

  var glb : glob_t;

  const err = glob(pattern:c_string, 0, c_nil, glb);

  for i in 0..chpl_glob_num(glb) - 1 do
    yield chpl_glob_index(glb, i): string;

  globfree(glb);
}

//
// findfiles() is a simple find-like utility implemented using the above routines
// * startdir: where to start when looking for files
// * recur: tells whether or not to descend recurisvely
// * dotfiles: tells whether or not to yield dotfiles
//
iter findfiles(startdir = ".", recur=false, dotfiles=false) {
  if (recur) then
    for subdir in walkdirs(startdir, dotfiles=dotfiles) do
      for file in listdir(subdir, dotfiles=dotfiles, dirs=false, files=true, listlinks=true) do
        yield subdir+"/"+file;
  else
    for file in listdir(startdir, dotfiles=dotfiles, dirs=false, files=true, listlinks=false) do
      yield startdir+"/"+file;
}


Adjust default n value.

Adjust default n value.

/* The Computer Language Benchmarks Game
   http://shootout.alioth.debian.org/

   contributed by Tom Hildebrandt, Brad Chamberlain, Lydia Duncan,
   and Thomas Van Doren
   derived from the GNU C version by Bonzini, Bartlett, and Mellor
*/

use GMP;

// Compute n digits of Pi, 10 000 by default to match benchmark expectation.
config const n = 10000;

proc main() {
  for (digit, i) in zip(genDigits(n), 1..) {
    write(digit);
    if i % 10 == 0 then
      writeln("\t:", i);
  }
}

iter genDigits(numDigits) {
  var numer = new BigInt(1),
    accum = new BigInt(0),
    denom = new BigInt(1),
    tmp1 = new BigInt(),
    tmp2 = new BigInt();

  var k: c_ulong;

  for i in 1..numDigits {
    do {
      do {
        k += 1;
        const y2 = 2 * k + 1;

        // Compute the next term.
        tmp1.mul_ui(numer, 2: c_ulong);
        accum.add(accum, tmp1);
        accum.mul_ui(accum, y2);
        numer.mul_ui(numer, k);
        denom.mul_ui(denom, y2);

        // Continue looping until the digit is ready.
      } while numer.cmp(accum) > 0; // numer > accum

      // Compute: numer * 3 + accum
      tmp1.mul_ui(numer, 3: c_ulong);
      tmp1.add(tmp1, accum);

      // tmp1 = tmp1 / denom; tmp2 = tmp1 % denom
      // tmp1 gets quotient, tmp2 gets remainder
      tmp1.div_qr(Round.DOWN, tmp2, tmp1, denom);

      // Now, if:
      //   (numer * 3 + accum) % denom + numer == (numer * 4 + accum) + numer
      tmp2.add(tmp2, numer);
    } while tmp2.cmp(denom) >= 0; // tmp2 >= denom

    // Compute and yield the digit.
    const digit = tmp1.get_ui();
    yield digit;

    // Eliminate digit.
    accum.submul_ui(denom, digit);
    accum.mul_ui(accum, 10: c_ulong);
    numer.mul_ui(numer, 10: c_ulong);
  }

  // Free the memory associated with these.
  delete numer;
  delete accum;
  delete denom;
  delete tmp1;
  delete tmp2;
}

/* The Computer Language Benchmarks Game
   http://shootout.alioth.debian.org/

   contributed by Tom Hildebrandt, Brad Chamberlain, Lydia Duncan,
   and Thomas Van Doren
   derived from the GNU C version by Bonzini, Bartlett, and Mellor
*/

use GMP;

// Compute n digits of Pi, 50 by default.
config const n = 50;

proc main() {
  for (digit, i) in zip(genDigits(n), 1..) {
    write(digit);
    if i % 10 == 0 then
      writeln("\t:", i);
  }
}

iter genDigits(numDigits) {
  var numer = new BigInt(1),
    accum = new BigInt(0),
    denom = new BigInt(1),
    tmp1 = new BigInt(),
    tmp2 = new BigInt();

  var k: c_ulong;

  for i in 1..numDigits {
    do {
      do {
        k += 1;
        const y2 = 2 * k + 1;

        // Compute the next term.
        tmp1.mul_ui(numer, 2: c_ulong);
        accum.add(accum, tmp1);
        accum.mul_ui(accum, y2);
        numer.mul_ui(numer, k);
        denom.mul_ui(denom, y2);

        // Continue looping until the digit is ready.
      } while numer.cmp(accum) > 0; // numer > accum

      // Compute: numer * 3 + accum
      tmp1.mul_ui(numer, 3: c_ulong);
      tmp1.add(tmp1, accum);

      // tmp1 = tmp1 / denom; tmp2 = tmp1 % denom
      // tmp1 gets quotient, tmp2 gets remainder
      tmp1.div_qr(Round.DOWN, tmp2, tmp1, denom);

      // Now, if:
      //   (numer * 3 + accum) % denom + numer == (numer * 4 + accum) + numer
      tmp2.add(tmp2, numer);
    } while tmp2.cmp(denom) >= 0; // tmp2 >= denom

    // Compute and yield the digit.
    const digit = tmp1.get_ui();
    yield digit;

    // Eliminate digit.
    accum.submul_ui(denom, digit);
    accum.mul_ui(accum, 10: c_ulong);
    numer.mul_ui(numer, 10: c_ulong);
  }

  // Free the memory associated with these.
  delete numer;
  delete accum;
  delete denom;
  delete tmp1;
  delete tmp2;
}


Whoops, forgot a line break!

Whoops, forgot a line break!

use FileSystem;
// Test the correctness of changing the mode of files and directories.  Assumes
// that the process umask is 0022.  Note: will break if umask is different.
config const permissions = 0o777;
var filename = "file";
var dirname = "dir";
chmod(filename, permissions);
chmod(dirname, permissions);


Range count bug fix -- allow and use tighter bounds.

The range specification 10..100 by 10 # 10 was generating a run-time error since
the bounds desired by the algorithm (10..109) lay beyond the user-specified
bounds.  Consensus so far is that the bounds returned by # should be clipped by
the user's bounds without warning.

We already perform a check to ensure that the original range is at least large
enough to produce the number of indices requested, so the only cases where
clipping will apply are those in which the specified opposite bound of the range
is between 0 (a tight bound) and the stride (non-inclusive on both ends).

git-svn-id: 88467cb1fb04b8a755be7e1ee1026be4190196ef@18714 3a8e244f-b0f2-452b-bcba-4c88e055c3ca

// ChapelRangeBase.chpl
//

use DSIUtil;

// Turns on range iterator debugging.
config param debugChapelRange = false;

//
// range type
//
//   parameterized by:
//        1) an integral element type,
//        2) whether low and/or high bounds exist, and
//        3) whether the stride is one or not.
//
// A range can only be aligned if it is strided.  Since alignments are taken
// modulo the stride, if the stride is one, even a nonzero alignment has no effect.
// The alignment of a range is relative to the low bound if it exists, otherwise
// relative to the high bound if it exists, otherwise absolute.
//
// The type of the stride is a signed type with the same number of bits as the
// index type.  This means that for an unsigned index type, a maximal range can
// be reached in no less than two strides.
//
enum BoundedRangeType { bounded, boundedLow, boundedHigh, boundedNone };

record rangeBase
{
  type idxType = int;                            // element type
  param boundedType: BoundedRangeType = BoundedRangeType.bounded; // bounded or not
  param stridable: bool = false;                 // range can be strided

  var _low: idxType = 1;                         // lower bound
  var _high: idxType = 0;                        // upper bound
  var _stride: chpl__signedType(idxType) = 1;    // signed stride of range
  var _alignment: idxType = 0;                   // alignment

  pragma "inline" proc low return _low;       // public getter for low bound
  pragma "inline" proc high return _high;     // public getter for high bound
  pragma "inline" proc stride return _stride; // public getter for stride
  pragma "inline" proc alignment return _alignment;        // public getter for alignment

}

//################################################################################
//# Constructors
//#

// Declare this as constructor, so we can capture range creation.
// If it is not a constructor, then the user can still create a maximal range
// (for example) without begin warned.
//
proc rangeBase.rangeBase(type idxType = int,
                param boundedType : BoundedRangeType = BoundedRangeType.bounded,
           param stridable : bool = false,
           _low : idxType = 1,
           _high : idxType = 0,
           _stride : chpl__signedType(idxType) = 1,
           _alignment: idxType = 0)
{
  this._low = _low;
  this._high = _high;
  if stridable then
  {
    this._stride = _stride;
    this._alignment = _alignment;
  }

  if warnMaximalRange
  {
    if boundedType == BoundedRangeType.bounded
    {
      if _low <= _high && this.last + _stride : idxType == this.first then
        writeln("Maximal range declared.  ",
        "A for loop on this range will execute zero times.  ",
        "Try using a wider index type.");
    }
  }
}

//################################################################################
//# Accessors
//#

// Returns the starting index (with minimal checks).
pragma "inline"
proc rangeBase.first
{
  if ! stridable then return _low;
  else return if _stride > 0 then this.alignedLow else this.alignedHigh;
}

// Returns the ending index (with minimal checks).
pragma "inline"
proc rangeBase.last
{
  if ! stridable then return _high;
  else return if _stride > 0 then this.alignedHigh else this.alignedLow;
}

// Returns the low index, properly aligned.
// The aligned low bound may be higher than the high bound.
pragma "inline"
proc rangeBase.alignedLow : idxType
{
  if ! this.hasLowBound() then
    halt("alignedLow -- No low bound defined for this range.");
  else
  {
    if ! stridable then return _low;
    else
      // Adjust _low upward by the difference between _alignment and _low.
      return _low + chpl__diffMod(_alignment, _low, _stride);
  }
}

// Returns the high index, properly aligned.
// The aligned high bound may be lower than the low bound.
pragma "inline"
proc rangeBase.alignedHigh : idxType
{
  if ! this.hasHighBound() then
    halt("alignedHigh -- No high bound defined for this range.");
  else
  {
    if ! stridable then return _high;
    else
      // Adjust _high downward by the difference between _high and _alignment.
      return _high - chpl__diffMod(_high, _alignment, _stride);
  }
}

// Returns the number of elements in this range.
proc rangeBase.length
{
  if boundedType != BoundedRangeType.bounded then
    compilerError("Unbounded range has infinite length.");
  else
  {
    if _low > _high then
      return 0:idxType;

    var s = abs(_stride): idxType;
    return (_high - this.alignedLow) / s + 1;
  }
}

//################################################################################
//# Predicates
//#

// Returns true if this range has a low bound.
proc rangeBase.hasLowBound() param
  return boundedType == BoundedRangeType.bounded || boundedType == BoundedRangeType.boundedLow;

// Returns true if this range has a high bound.
proc rangeBase.hasHighBound() param
  return boundedType == BoundedRangeType.bounded || boundedType == BoundedRangeType.boundedHigh;

pragma "inline"
proc rangeBase.hasFirst()
{
  if _stride > 0
  {
    if ! hasLowBound() then return false;
  }
  else
  {
    if ! hasHighBound() then return false;
  }
  return true;
}

pragma "inline"
proc rangeBase.hasLast()
{
  if _stride > 0
  {
    if ! hasHighBound() then return false;
  }
  else
  {
    if ! hasLowBound() then return false;
  }
  return true;
}

// Returns true if this range is naturally aligned, false otherwise.
proc rangeBase.isAligned()
  where this.boundedType == BoundedRangeType.bounded
{
  // If the stride is positive, we must be aligned on the low bound.
  if _stride > 0 then return this.alignedLow == _low;
  // If the stride is negative, we must be aligned on the high bound.
  if _stride < 0 then return this.alignedHigh == _high;
  // _stride == 0: ???
  return false;
}

pragma "inline"
proc rangeBase.isAligned()
  where this.boundedType == BoundedRangeType.boundedLow
{
  return this.alignedLow == _low;
}

pragma "inline"
proc rangeBase.isAligned()
  where this.boundedType == BoundedRangeType.boundedHigh
{
  return this.alignedHigh == _high;
}

pragma "inline"
proc rangeBase.isAligned()
{
  if _alignment == 0 then return true;
  return false;
}

// Returns true if i is in this range.
proc rangeBase.member(i: idxType)
{
  var al : idxType;
  if hasHighBound()
  {
    if i > _high then return false;
    al = this.alignedHigh;
  }
  if hasLowBound()
  {
    if i < _low then return false;
    al = this.alignedLow;
  }
  if stridable
  {
    var s = abs(_stride):idxType;
    // We don't have to use chpl__mod here, because we only care
    // whether the remainder is different from zero.
    if (i % s - al % s) % s != 0
      then return false;
  }
  return true;
}

// Returns true if the other range is contained within this one.
pragma "inline"
proc rangeBase.member(other: rangeBase(?))
{
  return other == this(other);
}

// Returns true if this range is equivalent to the other.
// Equivalent ranges produce the same index set.
//
// This routine relies on the assumption that
// the stride of an unstrided range is set to 1.
proc ==(r1: rangeBase(?), r2: rangeBase(?))
{
  // Cheapest test first!
  if r1._stride != r2._stride then return false;
  if r1.first != r2.first then return false;
  if r1.last != r2.last then return false;
  return true;
}

// This makes use of the fact that the default values for the
// stride and alignment fields are consistent, whether the two ranges
// being compared are stridable or not.
proc ident(r1: rangeBase(?), r2: rangeBase(?))
  where r1.idxType == r2.idxType &&
  r1.boundedType == r2.boundedType &&
  r1.stridable == r2.stridable
{
  if r1._low != r2._low then return false;
  if r1._high != r2._high then return false;
  if r1._stride != r2._stride then return false;
  if r1._alignment != r2._alignment then return false;
  return true;
}

proc ident(r1: rangeBase(?), r2: rangeBase(?))
  return false;

//////////////////////////////////////////////////////////////////////////////////
// Bounds checking
//
// returns true if other is in bounds of this for all specified
// bounds; these functions are used to determine if an array slice is
// valid.  We break out the boundedNone case in order to permit
// unbounded ranges to slice ranges of various index types -- otherwise
// we get a compiler error in the boundsCheck function.
//

pragma "inline"
proc rangeBase.boundsCheck(other: rangeBase(?e,?b,?s)) where b == BoundedRangeType.boundedNone
  return true;

proc rangeBase.boundsCheck(other: rangeBase(?e,?b,?s))
{
  var boundedOther: rangeBase(idxType, BoundedRangeType.bounded, s || this.stridable);

  if other.hasLowBound() then
    boundedOther._low = other._low;
  else
    boundedOther._low = _low;

  if other.hasHighBound() then
    boundedOther._high = other._high;
  else
    boundedOther._high = _high;

  boundedOther._stride = other._stride;
  boundedOther._alignment = other._alignment;

  return (boundedOther.length == 0) || member(boundedOther);
}

pragma "inline"
proc rangeBase.boundsCheck(other: idxType)
  return member(other);

//################################################################################
//# Member functions
//#

// Moves the low bound of the range up to the next alignment point.
proc rangeBase.alignLow()
{
  if ! stridable then return this;
  else _low = this.alignedLow;
  return this;
}

// Moves the high bound of the range down to the next alignment point.
proc rangeBase.alignHigh()
{
  if ! stridable then return this;
  else _high = this.alignedHigh;
  return this;
}

proc rangeBase.indexOrder(i: idxType)
{
  if ! member(i) then return (-1):idxType;
  if ! stridable then return i - _low;
  else
  {
    var s = abs(_stride):idxType;
    return (i - this.alignedLow) / s;
  }
}

//////////////////////////////////////////////////////////////////////////////////
// translate the indices in this range by i
//
// REVIEW: hilde
// Should member functions normally return new objects?
//
// NOTE: The casts below assume that the value will fit into
// idxType.  Handling errors when (down) casting is something
// we need to handle more generally in the future, so for
// consistency, we are not handling it here at all :-P
//
proc rangeBase.translate(i: integral)
{
  if _isSignedType(i.type) then
    return this + i:idxType;
  else if i >= 0 then return this + i:idxType;
  else return this - abs(i):idxType;
}

proc rangeBase.translate(i)
{
  compilerError("offsets must be of integral type");
}

// Return an interior portion of this range.
// TODO: hilde
// Alignment is set to true only if stridable is already set to true.
proc rangeBase.interior(i: idxType)
  where boundedType != BoundedRangeType.bounded
{
  compilerError("interior is not supported on unbounded ranges");
}

proc rangeBase.interior(i: idxType)
  where stridable == false
{
  if i < 0 then
    return new rangeBase(idxType, boundedType, false,
                     _low, _low- 1 - i);
  if i > 0 then
    return new rangeBase(idxType, boundedType, false,
                     _high + 1 - i, _high);
  // if i == 0 then
  return new rangeBase(idxType, boundedType, false,
                   _low, _high);
}

proc rangeBase.interior(i: idxType)
{
  if i < 0 then
    return new rangeBase(idxType, boundedType, true,
                     _low, _low-1-i, _stride, _alignment);
  if i > 0 then
    return new rangeBase(idxType, boundedType, true,
                     _high + 1 - i, _high, _stride, _alignment);
  // if i == 0 then
  return new rangeBase(idxType, boundedType, true,
                  _low, _high, _stride, _alignment);
}

// Return an exterior portion of this range.
proc rangeBase.exterior(i: idxType)
  where boundedType != BoundedRangeType.bounded
{
  compilerError("exterior is not supported on unbounded ranges");
}

proc rangeBase.exterior(i: idxType)
  where stridable == false
{
  if i < 0 then
    return new rangeBase(idxType, boundedType, false,
                     _low+i, _low-1);
  if i > 0 then
    return new rangeBase(idxType, boundedType, false,
                     _high+1, _high+i);
  // if i == 0 then
  return new rangeBase(idxType, boundedType, false,
                   _low, _high);
}

proc rangeBase.exterior(i: idxType)
{
  if i < 0 then
    return new rangeBase(idxType, boundedType, true,
                     _low - i, _low - 1, _stride, _alignment);
  if i > 0 then
    return new rangeBase(idxType, boundedType, true,
                     _high + 1, _high + i, _stride, _alignment);
  // if i == 0 then
  return new rangeBase(idxType, boundedType, true,
                   _low, _high, _stride, _alignment);
}

proc rangeBase.expand(i: idxType)
  where boundedType != BoundedRangeType.bounded
{
  compilerError("expand() is not supported on unbounded ranges");
}

// Returns an expanded range, or a contracted range if i < 0.
// The existing absolute alignment is preserved.
proc rangeBase.expand(i: idxType)
{
  return new rangeBase(idxType, boundedType, stridable,
                   _low-i, _high+i, _stride, _alignment);
}

//################################################################################
//# Syntax Functions
//#

// Assignment
proc =(r1: rangeBase(stridable=?s1), r2: rangeBase(stridable=?s2))
{
  if r1.boundedType != r2.boundedType then
    compilerError("type mismatch in assignment of ranges with different boundedType parameters");

  if !s1 && s2 then
    if r2._stride != 1 then
      halt("non-stridable range assigned non-unit stride");

  r1._low = r2._low;
  r1._high = r2._high;
  r1._stride = r2._stride;
  r1._alignment = r2._alignment;

  return r1;
}

//////////////////////////////////////////////////////////////////////////////////
// Range arithmetic.
//
// Shifts and entire range to the right or left.
// Absolute alignment is not preserved
// (That is, the alignment shifts along with the range.)
//
proc +(r: rangeBase(?e,?b,?s), i: integral)
{
  type resultType = (r._low+i).type;
  type strType = chpl__signedType(resultType);

  return new rangeBase(resultType, b, s,
                   r._low + i, r._high + i,
		   r._stride : strType, r._alignment + i : resultType);
}

pragma "inline"
proc +(i:integral, r: rangeBase(?e,?b,?s))
  return r + i;

proc -(r: rangeBase(?e,?b,?s), i: integral)
{
  type resultType = (r._low+i).type;
  type strType = chpl__signedType(resultType);

  return new rangeBase(resultType, b, s,
                   r._low - i, r._high - i,
		   r._stride : strType, r._alignment - i : resultType);
}

proc chpl__byHelp(r : rangeBase(?e, ?b, ?s), str : chpl__signedType(e))
{
  if str == 0 then
    halt("range cannot be strided by zero");

  var s = r._stride * str;
  var al : e = 0;
  if b == BoundedRangeType.boundedLow then al = r.alignedLow;
  if b == BoundedRangeType.boundedHigh then al = r.alignedHigh;
  if b == BoundedRangeType.bounded then
    al = if s > 0 then r.alignedLow else r.alignedHigh;

  return new rangeBase(e, b, true,
                   r._low, r._high, s, al);
}

proc chpl__by(r : rangeBase(?), str)
{
  type idxType = r.idxType;
  type strType = chpl__signedType(idxType);
  type argType = str.type;

  if (argType == strType) then return chpl__byHelp(r, str);
  else if (argType == idxType || chpl__legalIntCoerce(argType, strType)) then
    return chpl__byHelp(r, str:strType);
  else
    compilerError("type mismatch applying 'by' to range(", typeToString(idxType),
                  ") with ", typeToString(argType));
}

proc chpl__align(r : rangeBase(?e, ?b, ?s), algn)
{
  type idxType = r.idxType;
  type argType = algn.type;

  if argType == idxType || chpl__legalIntCoerce(argType, idxType) then
    // Note that aligning an unstrided range will set the field value,
    // but has no effect on the index set produced (a mod 1 == 0).
    return new rangeBase(e, b, s,
                     r._low, r._high, r._stride, algn);
  else
    compilerError("type mismatch applying 'align' to range(", typeToString(idxType),
                  ") with ", typeToString(argType));
}

// Apply a natural alignment to an existing range.
proc rangeBase.offset(offs : integral)
{
  type argType = offs.type;

  if argType == idxType || chpl__legalIntCoerce(argType, idxType)
  {
    if this.hasLowBound() then
      this._alignment = _low + offs;
    else if this.boundedType == BoundedRangeType.boundedHigh then
      this._alignment = _high + offs;
    else
      this._alignment = offs;
  }
  else
    compilerError("type mismatch applying 'absAlign' to range(",
              typeToString(idxType), ") with ", typeToString(argType));

  if ! stridable then
  {
    compilerWarning("Applying an alignment to an unstrided range has no effect.");
    this._alignment = 0; // Maintain the invariant.
  }
  return this;
}

// Composition
// Return the intersection of this and other.
proc rangeBase.this(other: rangeBase(?idxType2, ?boundedType, ?stridable))
{
  // Determine the boundedType of result
  proc computeBoundedType(r1, r2) param
  {
    param low = r1.hasLowBound() || r2.hasLowBound();
    param high = r1.hasHighBound() || r2.hasHighBound();
    if low && high then
      return BoundedRangeType.bounded;
    else if low then
      return BoundedRangeType.boundedLow;
    else if high then
      return BoundedRangeType.boundedHigh;
    else
      return BoundedRangeType.boundedNone;
  }

  // If this range is unbounded below, we use low from the other range,
  // so that max(lo1, lo2) == lo2.  etc.
  var lo1 = if hasLowBound() then this._low else other._low;
  var hi1 = if hasHighBound() then this._high else other._high;
  var st1 = abs(this._stride);

  var lo2 = if other.hasLowBound() then other._low else this._low;
  var hi2 = if other.hasHighBound() then other._high else this._high;
  var st2 = abs(other._stride);

  // If the result type is unsigned, don't let the low bound go negative.
  // This is a kludge.  We should really obey type coercion rules. (hilde)
  if (_isUnsignedType(idxType)) { if (lo1 < 0) then lo1 = 0; }

  var (g, x) = chpl__extendedEuclid(st1, st2);
  var lcm = st1 / g * st2;        // The LCM of the two strides.
  // The division must be done first to prevent overflow.

  var result = new rangeBase(idxType,
                         computeBoundedType(this, other),
                         this.stridable | other.stridable,
                         max(lo1, lo2):idxType,
                         min(hi1, hi2):idxType,
                         lcm:chpl__signedType(idxType));

  var al1 = (this._alignment % st1:idxType):int;
  var al2 = (other._alignment % st2:other.idxType):int;

  if (al2 - al1) % g != 0 then
    // empty intersection, return degenerate result
    (result._low, result._high, result._alignment) =
    (1:idxType, 0:idxType, 1:idxType);
    // _alignment == _low, so it won't print.
  else
  { // non-empty intersection

    // x and/or the diff may negative, even with a uint source range.
    var offset = (al2 - al1) * x;
    // offset is in the range [-(lcm-1), lcm-1]
    if offset < 0 then offset += lcm;

    // Now offset can be safely cast to idxType.
    result._alignment = al1:idxType + offset:idxType * st1:idxType / g:idxType;

    // We inherit the sign of the stride from the operand.
    if other._stride < 0 then
      result._stride = -result._stride;
  }

  return result;
}

//////////////////////////////////////////////////////////////////////////////////
// syntax functions for counted ranges
//

// Creates a new range from an existing range, but with the specified number of
// elements.
// The new range has the same stride and alignment as the existing range.
// If the argument n is positive, the new range contains
// the first n elements in the existing range.
// If the argument n is negative, the new range contains
// the last abs(n) elements in the existing range.

proc chpl__count(r:rangeBase(?), i:integral)
  where r.boundedType == BoundedRangeType.boundedNone
{
  compilerError("count operator is not defined for unbounded ranges");
}

proc chpl__count(r:rangeBase(?), i:integral)
{
  type resultType = (r._low+i).type;
  type strType = chpl__signedType(resultType);

  if (i == 0) then
    // Return a degenerate range.
    return new rangeBase(idxType = resultType,
                     boundedType = BoundedRangeType.bounded,
                     stridable = r.stridable,
                     _low = 1,
                     _high = 0,
                     _stride = r._stride,
                     _alignment = 1);

  if i > 0 && !r.hasFirst() then
    halt("With a nonzero count, the range must have a first index.");
  if i < 0 && !r.hasLast() then
    halt("With a negative count, the range must have a last index.");
  if r.boundedType == BoundedRangeType.bounded && i > r.length then
    halt("bounded range is too small to access ", i, " elements");

  // The distance between the first and last indices.
  var s = r._stride : strType;
  var diff = i : strType * s;

  var lo : resultType =
    if diff > 0 then r._low
    else chpl__add(r._high : resultType, (diff + 1): resultType);
  var hi : resultType =
    if diff < 0 then r._high
    else chpl__add(r._low : resultType, diff : resultType - 1);

  if r.hasLowBound() && lo < r._low then lo = r._low;
  if r.hasHighBound() && hi > r._high then hi = r._high;

  return new rangeBase(idxType = resultType,
                       boundedType = BoundedRangeType.bounded,
                       stridable = r.stridable,
                       _low = lo,
                       _high = hi,
                       _stride = r._stride : strType,
                       _alignment = r._alignment);
}

//################################################################################
//# Iterators
//#

// Default iterator optimized for unit stride
iter rangeBase.these()
{
  if boundedType != BoundedRangeType.bounded
  {
    if boundedType == BoundedRangeType.boundedNone then
      halt("iteration over a range with no bounds");
    if stridable
    {
      if boundedType == BoundedRangeType.boundedLow then
        if _stride < 0 then
          halt("iteration over range with negative stride but no high bound");
      if boundedType == BoundedRangeType.boundedHigh then
        if _stride > 0 then
          halt("iteration over range with positive stride but no low bound");
      var i = this.first;
      while true
      {
        yield i;
        i = i + _stride:idxType;
      }
    }
    else
    {
      if boundedType == BoundedRangeType.boundedHigh then
        halt("iteration over range with positive stride but no low bound");
      var i = _low;
      while true
      {
        yield i;
        i = i + 1;
      }
    }
  }
  else
  {
    // a bounded range ...

    // This case is written so that the only control is the loop test.
    // Zippered iterator inlining currently requires this.

    var i = this.first;
    var end : idxType;

    if stridable
    {
      end = if _low > _high then i else this.last + _stride:idxType;
      while i != end
      {
        yield i;
        i = i + _stride:idxType;
      }
    }
    else
    {
      end = if _low > _high then i else this.last + 1;
      while i != end
      {
        yield i;
        i = i + 1;
      }
    }
  }
}

iter rangeBase.these(param tag: iterator) where tag == iterator.leader
{
  // want "yield 0..length-1;"
  // but compilerError in length causes a problem because leaders are
  // resolved wherever an iterator is.
  if boundedType == BoundedRangeType.boundedNone then
    halt("iteration over a range with no bounds");

  if debugChapelRange then
    writeln("*** In range leader:"); // ", this);

  var v = this.length;
  var numChunks = _computeNumChunks(v);

  if debugChapelRange
  {
    writeln("*** RI: length=", v, " numChunks=", numChunks);
    writeln("*** RI: Using ", numChunks, " chunk(s)");
  }

  if (CHPL_TARGET_PLATFORM == "xmt")
  {
    var per_stream_i: uint(64) = 0;
    var total_streams_n: uint(64) = 0;

    __primitive_loop("xmt pragma forall i in n", per_stream_i,
                     total_streams_n) {
      const (lo,hi) = _computeBlock(v, total_streams_n, per_stream_i, v-1);
      yield tuple(lo..hi);
    }
  }
  else
  {
    if numChunks == 1 then
      yield tuple(0..v-1);
    else
    {
      coforall chunk in 0..numChunks-1
      {
        const (lo,hi) = _computeBlock(v, numChunks, chunk, v-1);
        if debugChapelRange then
          writeln("*** RI: tuple = ", tuple(lo..hi));
        yield tuple(lo..hi);
      }
    }
  }
}

iter rangeBase.these(param tag: iterator, follower) where tag == iterator.follower
{
  if boundedType == BoundedRangeType.boundedNone then
    halt("iteration over a range with no bounds");
  if follower.size != 1 then
    halt("iteration over a range with multi-dimensional iterator");

  if debugChapelRange then
    writeln("In range follower code: Following ", follower);

  var followThis = follower(1);

  if debugChapelRange then
    writeln("Range = ", followThis);

  // It would be nice to be able to factor out the repeated code below,
  // but what is the type of r?.
  if stridable
  {
    // r is a range which contains the next chunk of values controlled by followThis.
    // The range in followThis usually has a stride of 1 (optimization opportunity?).
    var r = (if _stride > 0 then
         _low + followThis.low*_stride:idxType.._low+followThis.high*_stride:idxType
       else
        _high + followThis.high*_stride:idxType.._high+followThis.low*_stride:idxType
      ) by _stride by followThis.stride;

    if debugChapelRange then
      writeln("Expanded range = ",r);

    for i in r
    {
      __primitive("noalias pragma");
      yield i;
    }
  }
  else // ! stridable
  {
    var r = _low+followThis;

    if debugChapelRange then
      writeln("Expanded range = ",r);

    for i in r
    {
      __primitive("noalias pragma");
      yield i;
    }
  }
}

//################################################################################
//# Utilities
//#

// Write implementation for ranges
proc rangeBase.writeThis(f: Writer)
{
  if hasLowBound() then
    f.write(_low);
  f.write("..");
  if hasHighBound() then
    f.write(_high);
  if _stride != 1 then
    f.write(" by ", _stride);

  // Write out the alignment only if it differs from natural alignment.
  // We take alignment modulo the stride for consistency.
  if ! isAligned() then
    f.write(" align ", chpl__mod(_alignment, _stride));
}

// Return a substring of a string with a range of indices.
pragma "inline" proc string.substring(r: rangeBase(?))
{
  if r.boundedType != BoundedRangeType.bounded then
    compilerError("substring indexing undefined on unbounded ranges");

  if r._stride != 1 then
    return __primitive("string_strided_select", this, r.alignedLow, r.alignedHigh, r._stride);
  else
    return __primitive("string_select", this, r.low, r.high);
}

//################################################################################
//# Internal helper functions.
//#

proc rangeBase.chpl__unTranslate(i: idxType)
{
  return this - i;
}

proc rangeBase.chpl__unTranslate(i)
{
  if _isSignedType(i.type) then
    return this - i;
  else
    return this + abs(i);
}

//////////////////////////////////////////////////////////////////////////////////
// TODO: hilde
// These functions should be migrated to a more global location.

//
// Return the number in the range 0 <= result < b that is congruent to a (mod b)
//
proc chpl__mod(dividend:integral, in modulus:integral)
{
  type dType = dividend.type;
  modulus = abs(modulus);
  // modulus is positive, so this cast is OK unless it is very large
  // and the dividend is signed.
  var m = modulus : dType;
  if m : modulus.type != modulus then
    halt("Modulus too large.");

  var tmp = dividend % m;
  if _isSignedType(dividend.type) then
    if tmp < 0 then tmp += m;

  return tmp;
}

// Performs safe subtraction in modulo space.
// "Safe" means that none of the calculations yields a result outside of
// [0, abs(mod)].
// It is assumed that abs(mod) can be represented in the type of the minuend.
// We currently assume that the built-in modulo operator always returns an
// integer in the range [0, mod-1].
//
proc chpl__diffMod(minuend : integral,
                   subtrahend : integral,
                   in modulus : integral) : minuend.type
  where minuend.type == subtrahend.type
{
  type minType = minuend.type;

  modulus = abs(modulus);
  var m = modulus : minType;
  if m : modulus.type != modulus then
    halt("Modulus too large.");

  var minMod = chpl__mod(minuend, m);
  var subMod = chpl__mod(subtrahend, m);

  return if minMod < subMod
    then m  - (subMod - minMod)
    else minMod - subMod;
}

proc chpl__diffMod(minuend : integral,
                   subtrahend : integral,
                   in modulus : integral)
{
  compilerError("chpl__diffMod -- Operand types must match.");
}

// Add two numbers together, and peg them to the min or max representable value
// if there is overflow.
// We might wish to add dialable run-time warning messages.
proc chpl__add(a: ?t, b: t)
{
  if !_isIntegralType(t) then
    compilerError("Values must be of integral type.");

  if a > 0 && b > 0 && b > max(t) - a then return max(t);
  if a < 0 && b < 0 && b < min(t) - a then return min(t);
  return a + b;
}

// Returns (gcd(u, v), x) where x is set such that
// u*x + v*y = gcd(u, v) assuming u and v are non-negative.
//
// source: Knuth Volume 2 --- Section 4.5.2
//
proc chpl__extendedEuclidHelper(u, v)
{
  var zero: u.type = 0;
  var one: u.type = 1;

  var U = (one, zero, u);
  var V = (zero, one, v);

  while V(3) != 0 do
    (U, V) = let q = U(3)/V(3) in (V, U - V * (q, q, q));

  return (U(3), U(1));
}

pragma "inline" proc chpl__extendedEuclid(u:int, v:int)
{ return chpl__extendedEuclidHelper(u,v); }

pragma "inline" proc chpl__extendedEuclid(u:int(64), v:int(64))
{ return chpl__extendedEuclidHelper(u,v); }

// ChapelRangeBase.chpl
//

use DSIUtil;

// Turns on range iterator debugging.
config param debugChapelRange = false;

//
// range type
//
//   parameterized by:
//        1) an integral element type,
//        2) whether low and/or high bounds exist, and
//        3) whether the stride is one or not.
//
// A range can only be aligned if it is strided.  Since alignments are taken
// modulo the stride, if the stride is one, even a nonzero alignment has no effect.
// The alignment of a range is relative to the low bound if it exists, otherwise
// relative to the high bound if it exists, otherwise absolute.
//
// The type of the stride is a signed type with the same number of bits as the
// index type.  This means that for an unsigned index type, a maximal range can
// be reached in no less than two strides.
//
enum BoundedRangeType { bounded, boundedLow, boundedHigh, boundedNone };

record rangeBase
{
  type idxType = int;                            // element type
  param boundedType: BoundedRangeType = BoundedRangeType.bounded; // bounded or not
  param stridable: bool = false;                 // range can be strided

  var _low: idxType = 1;                         // lower bound
  var _high: idxType = 0;                        // upper bound
  var _stride: chpl__signedType(idxType) = 1;    // signed stride of range
  var _alignment: idxType = 0;                   // alignment

  pragma "inline" proc low return _low;       // public getter for low bound
  pragma "inline" proc high return _high;     // public getter for high bound
  pragma "inline" proc stride return _stride; // public getter for stride
  pragma "inline" proc alignment return _alignment;        // public getter for alignment

}

//################################################################################
//# Constructors
//#

// Declare this as constructor, so we can capture range creation.
// If it is not a constructor, then the user can still create a maximal range
// (for example) without begin warned.
//
proc rangeBase.rangeBase(type idxType = int,
                param boundedType : BoundedRangeType = BoundedRangeType.bounded,
           param stridable : bool = false,
           _low : idxType = 1,
           _high : idxType = 0,
           _stride : chpl__signedType(idxType) = 1,
           _alignment: idxType = 0)
{
  this._low = _low;
  this._high = _high;
  if stridable then
  {
    this._stride = _stride;
    this._alignment = _alignment;
  }

  if warnMaximalRange
  {
    if boundedType == BoundedRangeType.bounded
    {
      if _low <= _high && this.last + _stride : idxType == this.first then
        writeln("Maximal range declared.  ",
        "A for loop on this range will execute zero times.  ",
        "Try using a wider index type.");
    }
  }
}

//################################################################################
//# Accessors
//#

// Returns the starting index (with minimal checks).
pragma "inline"
proc rangeBase.first
{
  if ! stridable then return _low;
  else return if _stride > 0 then this.alignedLow else this.alignedHigh;
}

// Returns the ending index (with minimal checks).
pragma "inline"
proc rangeBase.last
{
  if ! stridable then return _high;
  else return if _stride > 0 then this.alignedHigh else this.alignedLow;
}

// Returns the low index, properly aligned.
// The aligned low bound may be higher than the high bound.
pragma "inline"
proc rangeBase.alignedLow : idxType
{
  if ! this.hasLowBound() then
    halt("alignedLow -- No low bound defined for this range.");
  else
  {
    if ! stridable then return _low;
    else
      // Adjust _low upward by the difference between _alignment and _low.
      return _low + chpl__diffMod(_alignment, _low, _stride);
  }
}

// Returns the high index, properly aligned.
// The aligned high bound may be lower than the low bound.
pragma "inline"
proc rangeBase.alignedHigh : idxType
{
  if ! this.hasHighBound() then
    halt("alignedHigh -- No high bound defined for this range.");
  else
  {
    if ! stridable then return _high;
    else
      // Adjust _high downward by the difference between _high and _alignment.
      return _high - chpl__diffMod(_high, _alignment, _stride);
  }
}

// Returns the number of elements in this range.
proc rangeBase.length
{
  if boundedType != BoundedRangeType.bounded then
    compilerError("Unbounded range has infinite length.");
  else
  {
    if _low > _high then
      return 0:idxType;

    var s = abs(_stride): idxType;
    return (_high - this.alignedLow) / s + 1;
  }
}

//################################################################################
//# Predicates
//#

// Returns true if this range has a low bound.
proc rangeBase.hasLowBound() param
  return boundedType == BoundedRangeType.bounded || boundedType == BoundedRangeType.boundedLow;

// Returns true if this range has a high bound.
proc rangeBase.hasHighBound() param
  return boundedType == BoundedRangeType.bounded || boundedType == BoundedRangeType.boundedHigh;

pragma "inline"
proc rangeBase.hasFirst()
{
  if _stride > 0
  {
    if ! hasLowBound() then return false;
  }
  else
  {
    if ! hasHighBound() then return false;
  }
  return true;
}

pragma "inline"
proc rangeBase.hasLast()
{
  if _stride > 0
  {
    if ! hasHighBound() then return false;
  }
  else
  {
    if ! hasLowBound() then return false;
  }
  return true;
}

// Returns true if this range is naturally aligned, false otherwise.
proc rangeBase.isAligned()
  where this.boundedType == BoundedRangeType.bounded
{
  // If the stride is positive, we must be aligned on the low bound.
  if _stride > 0 then return this.alignedLow == _low;
  // If the stride is negative, we must be aligned on the high bound.
  if _stride < 0 then return this.alignedHigh == _high;
  // _stride == 0: ???
  return false;
}

pragma "inline"
proc rangeBase.isAligned()
  where this.boundedType == BoundedRangeType.boundedLow
{
  return this.alignedLow == _low;
}

pragma "inline"
proc rangeBase.isAligned()
  where this.boundedType == BoundedRangeType.boundedHigh
{
  return this.alignedHigh == _high;
}

pragma "inline"
proc rangeBase.isAligned()
{
  if _alignment == 0 then return true;
  return false;
}

// Returns true if i is in this range.
proc rangeBase.member(i: idxType)
{
  var al : idxType;
  if hasHighBound()
  {
    if i > _high then return false;
    al = this.alignedHigh;
  }
  if hasLowBound()
  {
    if i < _low then return false;
    al = this.alignedLow;
  }
  if stridable
  {
    var s = abs(_stride):idxType;
    // We don't have to use chpl__mod here, because we only care
    // whether the remainder is different from zero.
    if (i % s - al % s) % s != 0
      then return false;
  }
  return true;
}

// Returns true if the other range is contained within this one.
pragma "inline"
proc rangeBase.member(other: rangeBase(?))
{
  return other == this(other);
}

// Returns true if this range is equivalent to the other.
// Equivalent ranges produce the same index set.
//
// This routine relies on the assumption that
// the stride of an unstrided range is set to 1.
proc ==(r1: rangeBase(?), r2: rangeBase(?))
{
  // Cheapest test first!
  if r1._stride != r2._stride then return false;
  if r1.first != r2.first then return false;
  if r1.last != r2.last then return false;
  return true;
}

// This makes use of the fact that the default values for the
// stride and alignment fields are consistent, whether the two ranges
// being compared are stridable or not.
proc ident(r1: rangeBase(?), r2: rangeBase(?))
  where r1.idxType == r2.idxType &&
  r1.boundedType == r2.boundedType &&
  r1.stridable == r2.stridable
{
  if r1._low != r2._low then return false;
  if r1._high != r2._high then return false;
  if r1._stride != r2._stride then return false;
  if r1._alignment != r2._alignment then return false;
  return true;
}

proc ident(r1: rangeBase(?), r2: rangeBase(?))
  return false;

//////////////////////////////////////////////////////////////////////////////////
// Bounds checking
//
// returns true if other is in bounds of this for all specified
// bounds; these functions are used to determine if an array slice is
// valid.  We break out the boundedNone case in order to permit
// unbounded ranges to slice ranges of various index types -- otherwise
// we get a compiler error in the boundsCheck function.
//

pragma "inline"
proc rangeBase.boundsCheck(other: rangeBase(?e,?b,?s)) where b == BoundedRangeType.boundedNone
  return true;

proc rangeBase.boundsCheck(other: rangeBase(?e,?b,?s))
{
  var boundedOther: rangeBase(idxType, BoundedRangeType.bounded, s || this.stridable);

  if other.hasLowBound() then
    boundedOther._low = other._low;
  else
    boundedOther._low = _low;

  if other.hasHighBound() then
    boundedOther._high = other._high;
  else
    boundedOther._high = _high;

  boundedOther._stride = other._stride;
  boundedOther._alignment = other._alignment;

  return (boundedOther.length == 0) || member(boundedOther);
}

pragma "inline"
proc rangeBase.boundsCheck(other: idxType)
  return member(other);

//################################################################################
//# Member functions
//#

// Moves the low bound of the range up to the next alignment point.
proc rangeBase.alignLow()
{
  if ! stridable then return this;
  else _low = this.alignedLow;
  return this;
}

// Moves the high bound of the range down to the next alignment point.
proc rangeBase.alignHigh()
{
  if ! stridable then return this;
  else _high = this.alignedHigh;
  return this;
}

proc rangeBase.indexOrder(i: idxType)
{
  if ! member(i) then return (-1):idxType;
  if ! stridable then return i - _low;
  else
  {
    var s = abs(_stride):idxType;
    return (i - this.alignedLow) / s;
  }
}

//////////////////////////////////////////////////////////////////////////////////
// translate the indices in this range by i
//
// REVIEW: hilde
// Should member functions normally return new objects?
//
// NOTE: The casts below assume that the value will fit into
// idxType.  Handling errors when (down) casting is something
// we need to handle more generally in the future, so for
// consistency, we are not handling it here at all :-P
//
proc rangeBase.translate(i: integral)
{
  if _isSignedType(i.type) then
    return this + i:idxType;
  else if i >= 0 then return this + i:idxType;
  else return this - abs(i):idxType;
}

proc rangeBase.translate(i)
{
  compilerError("offsets must be of integral type");
}

// Return an interior portion of this range.
// TODO: hilde
// Alignment is set to true only if stridable is already set to true.
proc rangeBase.interior(i: idxType)
  where boundedType != BoundedRangeType.bounded
{
  compilerError("interior is not supported on unbounded ranges");
}

proc rangeBase.interior(i: idxType)
  where stridable == false
{
  if i < 0 then
    return new rangeBase(idxType, boundedType, false,
                     _low, _low- 1 - i);
  if i > 0 then
    return new rangeBase(idxType, boundedType, false,
                     _high + 1 - i, _high);
  // if i == 0 then
  return new rangeBase(idxType, boundedType, false,
                   _low, _high);
}

proc rangeBase.interior(i: idxType)
{
  if i < 0 then
    return new rangeBase(idxType, boundedType, true,
                     _low, _low-1-i, _stride, _alignment);
  if i > 0 then
    return new rangeBase(idxType, boundedType, true,
                     _high + 1 - i, _high, _stride, _alignment);
  // if i == 0 then
  return new rangeBase(idxType, boundedType, true,
                  _low, _high, _stride, _alignment);
}

// Return an exterior portion of this range.
proc rangeBase.exterior(i: idxType)
  where boundedType != BoundedRangeType.bounded
{
  compilerError("exterior is not supported on unbounded ranges");
}

proc rangeBase.exterior(i: idxType)
  where stridable == false
{
  if i < 0 then
    return new rangeBase(idxType, boundedType, false,
                     _low+i, _low-1);
  if i > 0 then
    return new rangeBase(idxType, boundedType, false,
                     _high+1, _high+i);
  // if i == 0 then
  return new rangeBase(idxType, boundedType, false,
                   _low, _high);
}

proc rangeBase.exterior(i: idxType)
{
  if i < 0 then
    return new rangeBase(idxType, boundedType, true,
                     _low - i, _low - 1, _stride, _alignment);
  if i > 0 then
    return new rangeBase(idxType, boundedType, true,
                     _high + 1, _high + i, _stride, _alignment);
  // if i == 0 then
  return new rangeBase(idxType, boundedType, true,
                   _low, _high, _stride, _alignment);
}

proc rangeBase.expand(i: idxType)
  where boundedType != BoundedRangeType.bounded
{
  compilerError("expand() is not supported on unbounded ranges");
}

// Returns an expanded range, or a contracted range if i < 0.
// The existing absolute alignment is preserved.
proc rangeBase.expand(i: idxType)
{
  return new rangeBase(idxType, boundedType, stridable,
                   _low-i, _high+i, _stride, _alignment);
}

//################################################################################
//# Syntax Functions
//#

// Assignment
proc =(r1: rangeBase(stridable=?s1), r2: rangeBase(stridable=?s2))
{
  if r1.boundedType != r2.boundedType then
    compilerError("type mismatch in assignment of ranges with different boundedType parameters");

  if !s1 && s2 then
    if r2._stride != 1 then
      halt("non-stridable range assigned non-unit stride");

  r1._low = r2._low;
  r1._high = r2._high;
  r1._stride = r2._stride;
  r1._alignment = r2._alignment;

  return r1;
}

//////////////////////////////////////////////////////////////////////////////////
// Range arithmetic.
//
// Shifts and entire range to the right or left.
// Absolute alignment is not preserved
// (That is, the alignment shifts along with the range.)
//
proc +(r: rangeBase(?e,?b,?s), i: integral)
{
  type resultType = (r._low+i).type;
  type strType = chpl__signedType(resultType);

  return new rangeBase(resultType, b, s,
                   r._low + i, r._high + i,
		   r._stride : strType, r._alignment + i : resultType);
}

pragma "inline"
proc +(i:integral, r: rangeBase(?e,?b,?s))
  return r + i;

proc -(r: rangeBase(?e,?b,?s), i: integral)
{
  type resultType = (r._low+i).type;
  type strType = chpl__signedType(resultType);

  return new rangeBase(resultType, b, s,
                   r._low - i, r._high - i,
		   r._stride : strType, r._alignment - i : resultType);
}

proc chpl__byHelp(r : rangeBase(?e, ?b, ?s), str : chpl__signedType(e))
{
  if str == 0 then
    halt("range cannot be strided by zero");

  var s = r._stride * str;
  var al : e = 0;
  if b == BoundedRangeType.boundedLow then al = r.alignedLow;
  if b == BoundedRangeType.boundedHigh then al = r.alignedHigh;
  if b == BoundedRangeType.bounded then
    al = if s > 0 then r.alignedLow else r.alignedHigh;

  return new rangeBase(e, b, true,
                   r._low, r._high, s, al);
}

proc chpl__by(r : rangeBase(?), str)
{
  type idxType = r.idxType;
  type strType = chpl__signedType(idxType);
  type argType = str.type;

  if (argType == strType) then return chpl__byHelp(r, str);
  else if (argType == idxType || chpl__legalIntCoerce(argType, strType)) then
    return chpl__byHelp(r, str:strType);
  else
    compilerError("type mismatch applying 'by' to range(", typeToString(idxType),
                  ") with ", typeToString(argType));
}

proc chpl__align(r : rangeBase(?e, ?b, ?s), algn)
{
  type idxType = r.idxType;
  type argType = algn.type;

  if argType == idxType || chpl__legalIntCoerce(argType, idxType) then
    // Note that aligning an unstrided range will set the field value,
    // but has no effect on the index set produced (a mod 1 == 0).
    return new rangeBase(e, b, s,
                     r._low, r._high, r._stride, algn);
  else
    compilerError("type mismatch applying 'align' to range(", typeToString(idxType),
                  ") with ", typeToString(argType));
}

// Apply a natural alignment to an existing range.
proc rangeBase.offset(offs : integral)
{
  type argType = offs.type;

  if argType == idxType || chpl__legalIntCoerce(argType, idxType)
  {
    if this.hasLowBound() then
      this._alignment = _low + offs;
    else if this.boundedType == BoundedRangeType.boundedHigh then
      this._alignment = _high + offs;
    else
      this._alignment = offs;
  }
  else
    compilerError("type mismatch applying 'absAlign' to range(",
              typeToString(idxType), ") with ", typeToString(argType));

  if ! stridable then
  {
    compilerWarning("Applying an alignment to an unstrided range has no effect.");
    this._alignment = 0; // Maintain the invariant.
  }
  return this;
}

// Composition
// Return the intersection of this and other.
proc rangeBase.this(other: rangeBase(?idxType2, ?boundedType, ?stridable))
{
  // Determine the boundedType of result
  proc computeBoundedType(r1, r2) param
  {
    param low = r1.hasLowBound() || r2.hasLowBound();
    param high = r1.hasHighBound() || r2.hasHighBound();
    if low && high then
      return BoundedRangeType.bounded;
    else if low then
      return BoundedRangeType.boundedLow;
    else if high then
      return BoundedRangeType.boundedHigh;
    else
      return BoundedRangeType.boundedNone;
  }

  // If this range is unbounded below, we use low from the other range,
  // so that max(lo1, lo2) == lo2.  etc.
  var lo1 = if hasLowBound() then this._low else other._low;
  var hi1 = if hasHighBound() then this._high else other._high;
  var st1 = abs(this._stride);

  var lo2 = if other.hasLowBound() then other._low else this._low;
  var hi2 = if other.hasHighBound() then other._high else this._high;
  var st2 = abs(other._stride);

  // If the result type is unsigned, don't let the low bound go negative.
  // This is a kludge.  We should really obey type coercion rules. (hilde)
  if (_isUnsignedType(idxType)) { if (lo1 < 0) then lo1 = 0; }

  var (g, x) = chpl__extendedEuclid(st1, st2);
  var lcm = st1 / g * st2;        // The LCM of the two strides.
  // The division must be done first to prevent overflow.

  var result = new rangeBase(idxType,
                         computeBoundedType(this, other),
                         this.stridable | other.stridable,
                         max(lo1, lo2):idxType,
                         min(hi1, hi2):idxType,
                         lcm:chpl__signedType(idxType));

  var al1 = (this._alignment % st1:idxType):int;
  var al2 = (other._alignment % st2:other.idxType):int;

  if (al2 - al1) % g != 0 then
    // empty intersection, return degenerate result
    (result._low, result._high, result._alignment) =
    (1:idxType, 0:idxType, 1:idxType);
    // _alignment == _low, so it won't print.
  else
  { // non-empty intersection

    // x and/or the diff may negative, even with a uint source range.
    var offset = (al2 - al1) * x;
    // offset is in the range [-(lcm-1), lcm-1]
    if offset < 0 then offset += lcm;

    // Now offset can be safely cast to idxType.
    result._alignment = al1:idxType + offset:idxType * st1:idxType / g:idxType;

    // We inherit the sign of the stride from the operand.
    if other._stride < 0 then
      result._stride = -result._stride;
  }

  return result;
}

//////////////////////////////////////////////////////////////////////////////////
// syntax functions for counted ranges
//

// Creates a new range from an existing range, but with the specified number of
// elements.
// The new range has the same stride and alignment as the existing range.
// If the argument n is positive, the new range contains
// the first n elements in the existing range.
// If the argument n is negative, the new range contains
// the last abs(n) elements in the existing range.

proc chpl__count(r:rangeBase(?), i:integral)
  where r.boundedType == BoundedRangeType.boundedNone
{
  compilerError("count operator is not defined for unbounded ranges");
}

proc chpl__count(r:rangeBase(?), i:integral)
{
  type resultType = (r._low+i).type;
  type strType = chpl__signedType(resultType);

  if (i == 0) then
    // Return a degenerate range.
    return new rangeBase(idxType = resultType,
                     boundedType = BoundedRangeType.bounded,
                     stridable = r.stridable,
                     _low = 1,
                     _high = 0,
                     _stride = r._stride,
                     _alignment = 1);

  if i > 0 && !r.hasFirst() then
    halt("With a nonzero count, the range must have a first index.");
  if i < 0 && !r.hasLast() then
    halt("With a negative count, the range must have a last index.");
  if r.boundedType == BoundedRangeType.bounded && i > r.length then
    halt("bounded range is too small to access ", i, " elements");

  // The distance between the first and last indices.
  var s = r._stride : strType;
  var diff = i : strType * s;

  var lo : resultType =
    if diff > 0 then r._low
    else chpl__add(r._high : resultType, (diff + 1): resultType);
  var hi : resultType =
    if diff < 0 then r._high
    else chpl__add(r._low : resultType, diff : resultType - 1);

  if r.hasLowBound() && lo < r._low ||
     r.hasHighBound() && hi > r._high then
    halt("Range is too small to count off ", i, " elements.");

  return new rangeBase(idxType = resultType,
                   boundedType = BoundedRangeType.bounded,
                   stridable = r.stridable,
                   _low = lo,
                   _high = hi,
                   _stride = r._stride : strType,
                   _alignment = r._alignment);
}

//################################################################################
//# Iterators
//#

// Default iterator optimized for unit stride
iter rangeBase.these()
{
  if boundedType != BoundedRangeType.bounded
  {
    if boundedType == BoundedRangeType.boundedNone then
      halt("iteration over a range with no bounds");
    if stridable
    {
      if boundedType == BoundedRangeType.boundedLow then
        if _stride < 0 then
          halt("iteration over range with negative stride but no high bound");
      if boundedType == BoundedRangeType.boundedHigh then
        if _stride > 0 then
          halt("iteration over range with positive stride but no low bound");
      var i = this.first;
      while true
      {
        yield i;
        i = i + _stride:idxType;
      }
    }
    else
    {
      if boundedType == BoundedRangeType.boundedHigh then
        halt("iteration over range with positive stride but no low bound");
      var i = _low;
      while true
      {
        yield i;
        i = i + 1;
      }
    }
  }
  else
  {
    // a bounded range ...

    // This case is written so that the only control is the loop test.
    // Zippered iterator inlining currently requires this.

    var i = this.first;
    var end : idxType;

    if stridable
    {
      end = if _low > _high then i else this.last + _stride:idxType;
      while i != end
      {
        yield i;
        i = i + _stride:idxType;
      }
    }
    else
    {
      end = if _low > _high then i else this.last + 1;
      while i != end
      {
        yield i;
        i = i + 1;
      }
    }
  }
}

iter rangeBase.these(param tag: iterator) where tag == iterator.leader
{
  // want "yield 0..length-1;"
  // but compilerError in length causes a problem because leaders are
  // resolved wherever an iterator is.
  if boundedType == BoundedRangeType.boundedNone then
    halt("iteration over a range with no bounds");

  if debugChapelRange then
    writeln("*** In range leader:"); // ", this);

  var v = this.length;
  var numChunks = _computeNumChunks(v);

  if debugChapelRange
  {
    writeln("*** RI: length=", v, " numChunks=", numChunks);
    writeln("*** RI: Using ", numChunks, " chunk(s)");
  }

  if (CHPL_TARGET_PLATFORM == "xmt")
  {
    var per_stream_i: uint(64) = 0;
    var total_streams_n: uint(64) = 0;

    __primitive_loop("xmt pragma forall i in n", per_stream_i,
                     total_streams_n) {
      const (lo,hi) = _computeBlock(v, total_streams_n, per_stream_i, v-1);
      yield tuple(lo..hi);
    }
  }
  else
  {
    if numChunks == 1 then
      yield tuple(0..v-1);
    else
    {
      coforall chunk in 0..numChunks-1
      {
        const (lo,hi) = _computeBlock(v, numChunks, chunk, v-1);
        if debugChapelRange then
          writeln("*** RI: tuple = ", tuple(lo..hi));
        yield tuple(lo..hi);
      }
    }
  }
}

iter rangeBase.these(param tag: iterator, follower) where tag == iterator.follower
{
  if boundedType == BoundedRangeType.boundedNone then
    halt("iteration over a range with no bounds");
  if follower.size != 1 then
    halt("iteration over a range with multi-dimensional iterator");

  if debugChapelRange then
    writeln("In range follower code: Following ", follower);

  var followThis = follower(1);

  if debugChapelRange then
    writeln("Range = ", followThis);

  // It would be nice to be able to factor out the repeated code below,
  // but what is the type of r?.
  if stridable
  {
    // r is a range which contains the next chunk of values controlled by followThis.
    // The range in followThis usually has a stride of 1 (optimization opportunity?).
    var r = (if _stride > 0 then
         _low + followThis.low*_stride:idxType.._low+followThis.high*_stride:idxType
       else
        _high + followThis.high*_stride:idxType.._high+followThis.low*_stride:idxType
      ) by _stride by followThis.stride;

    if debugChapelRange then
      writeln("Expanded range = ",r);

    for i in r
    {
      __primitive("noalias pragma");
      yield i;
    }
  }
  else // ! stridable
  {
    var r = _low+followThis;

    if debugChapelRange then
      writeln("Expanded range = ",r);

    for i in r
    {
      __primitive("noalias pragma");
      yield i;
    }
  }
}

//################################################################################
//# Utilities
//#

// Write implementation for ranges
proc rangeBase.writeThis(f: Writer)
{
  if hasLowBound() then
    f.write(_low);
  f.write("..");
  if hasHighBound() then
    f.write(_high);
  if _stride != 1 then
    f.write(" by ", _stride);

  // Write out the alignment only if it differs from natural alignment.
  // We take alignment modulo the stride for consistency.
  if ! isAligned() then
    f.write(" align ", chpl__mod(_alignment, _stride));
}

// Return a substring of a string with a range of indices.
pragma "inline" proc string.substring(r: rangeBase(?))
{
  if r.boundedType != BoundedRangeType.bounded then
    compilerError("substring indexing undefined on unbounded ranges");

  if r._stride != 1 then
    return __primitive("string_strided_select", this, r.alignedLow, r.alignedHigh, r._stride);
  else
    return __primitive("string_select", this, r.low, r.high);
}

//################################################################################
//# Internal helper functions.
//#

proc rangeBase.chpl__unTranslate(i: idxType)
{
  return this - i;
}

proc rangeBase.chpl__unTranslate(i)
{
  if _isSignedType(i.type) then
    return this - i;
  else
    return this + abs(i);
}

//////////////////////////////////////////////////////////////////////////////////
// TODO: hilde
// These functions should be migrated to a more global location.

//
// Return the number in the range 0 <= result < b that is congruent to a (mod b)
//
proc chpl__mod(dividend:integral, in modulus:integral)
{
  type dType = dividend.type;
  modulus = abs(modulus);
  // modulus is positive, so this cast is OK unless it is very large
  // and the dividend is signed.
  var m = modulus : dType;
  if m : modulus.type != modulus then
    halt("Modulus too large.");

  var tmp = dividend % m;
  if _isSignedType(dividend.type) then
    if tmp < 0 then tmp += m;

  return tmp;
}

// Performs safe subtraction in modulo space.
// "Safe" means that none of the calculations yields a result outside of
// [0, abs(mod)].
// It is assumed that abs(mod) can be represented in the type of the minuend.
// We currently assume that the built-in modulo operator always returns an
// integer in the range [0, mod-1].
//
proc chpl__diffMod(minuend : integral,
                   subtrahend : integral,
                   in modulus : integral) : minuend.type
  where minuend.type == subtrahend.type
{
  type minType = minuend.type;

  modulus = abs(modulus);
  var m = modulus : minType;
  if m : modulus.type != modulus then
    halt("Modulus too large.");

  var minMod = chpl__mod(minuend, m);
  var subMod = chpl__mod(subtrahend, m);

  return if minMod < subMod
    then m  - (subMod - minMod)
    else minMod - subMod;
}

proc chpl__diffMod(minuend : integral,
                   subtrahend : integral,
                   in modulus : integral)
{
  compilerError("chpl__diffMod -- Operand types must match.");
}

// Add two numbers together, and peg them to the min or max representable value
// if there is overflow.
// We might wish to add dialable run-time warning messages.
proc chpl__add(a: ?t, b: t)
{
  if !_isIntegralType(t) then
    compilerError("Values must be of integral type.");

  if a > 0 && b > 0 && b > max(t) - a then return max(t);
  if a < 0 && b < 0 && b < min(t) - a then return min(t);
  return a + b;
}

// Returns (gcd(u, v), x) where x is set such that
// u*x + v*y = gcd(u, v) assuming u and v are non-negative.
//
// source: Knuth Volume 2 --- Section 4.5.2
//
proc chpl__extendedEuclidHelper(u, v)
{
  var zero: u.type = 0;
  var one: u.type = 1;

  var U = (one, zero, u);
  var V = (zero, one, v);

  while V(3) != 0 do
    (U, V) = let q = U(3)/V(3) in (V, U - V * (q, q, q));

  return (U(3), U(1));
}

pragma "inline" proc chpl__extendedEuclid(u:int, v:int)
{ return chpl__extendedEuclidHelper(u,v); }

pragma "inline" proc chpl__extendedEuclid(u:int(64), v:int(64))
{ return chpl__extendedEuclidHelper(u,v); }