Adjusted the attention span of rock, paper, scissors players
to reduce the probability that the taskParallel regression test will fail during nightly tests

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

// This example illustrates Chapel's parallel tasking features,
// namely the begin, cobegin, coforall, and sync statements,
// as well as sync variables.

// This example is inspired by an imaginary family trip to an out-of-town
// soccer tournament.  It makes use of a random number generator, whose code
// appears near the end of this file.

use Time;
// This initializes the seed used for the random number generator.
var seed: sync uint = getCurrentTime() : uint;

var notThereYet = true;

// The begin statement spawns off a thread of execution that is
// independent from the rest of the program.  In this case, imagine a
// younger member of the family who periodically asks, "Are we there
// yet?" until someone else gets fed up with the incessant questions.

begin
  while notThereYet {
    writeln ("Are we there yet?");
    var delay = RandomNumber() * 4.0;
    sleep (delay : uint);  // wait between 0 and 3 seconds before asking again
  }

// Here's another independent thread of execution.
// When someone (perhaps the father) gets fed up after some period of time,
// he or she gets yells "Shut up!"
begin {
  var delay = RandomNumber() * 8.0 + 5.0;
  sleep (delay : uint);
  notThereYet = false;
  writeln ("Shut up!");
}

// While all the above is going on, some of the siblings decide to play a game
// of rock, paper, scissors.
writeln ("Want to play rock, paper, scissors?");

enum choices {rock, paper, scissors};

// Sync variables are useful for synchronizing between various threads of
// execution.  Besides containing a value, they also can oscillate between an
// empty state and a full state.  Usually, when a sync variable is empty,
// it means it is in the process of being modified, or some thread of execution
// is using some resource associated with this variable.  When this thread of
// execution no longer needs the variable or associated resource, it
// will change the state back to full.  Meanwhile, any other thread of
// execution that wishes to have access to the sync variable is
// blocked until the state of the variable becomes full.

// For the game of rock, paper, scissors, there will be three persons involved,
// represented by three independent threads of execution.  Two people actually
// play the game, while the third person acts as a referee, deciding who wins
// each round of the game.  At some point, one of the three announces he/she is
// tired of playing, at which time all three stop playing.

// This array contains the choice each player makes (rock, paper, or scissors)
// for a given round of the game.  When the state is full, it means
// the associated player has made his/her choice.  When the state is
// empty, it means the referee has seen the choice the player made.
var choice: [1..2] sync choices;

// When full, each element of this array informs the associated player that the
// referee is ready for the next round of the game.
var refereeReady: [1..2] sync bool;

// This variable informs the people involved in the game if someone is tired of
// playing.
var notTired: sync bool = true;

// Each statement of the cobegin statement is an independent thread of
// execution.  In this case, there are three, each corresponding to
// one of the persons involved in the game of rock, paper, scissors.
// Before continuing past a cobegin statement, all threads of
// execution introduced by the cobegin statement must have finished
// execution.  Since this is the last thing in this program, the
// entire program terminates once the game is over, or the person
// stops asking, "Are we there yet?", whichever happens later.
cobegin {
  player(1);
  player(2);
  referee();
}

// The following function implements the behavior of each player.
// There are two components to the behavior: one is to make a choice
// (rock, paper, or scissors) for each round; the other is the
// attention span the person has.
def player(num) {

  // The sync statement is used to introduce synchronization points in
  // a program. Before continuing past a sync statement, all threads
  // of execution that began inside the sync statement must have
  // terminated.  The sync statement is similar to a cobegin
  // statement, but compare how the behavior of the referee is
  // implemented to see how it differs from a cobegin statement.

  sync {

    // This begin statement implements the attention span the player has.
    begin {
      var delay = RandomNumber() * 10.0 + 3.0;
      sleep (delay : uint);
      // If this is the first person to get tired, he announces he's tired.
      if notTired {
        notTired = false;
        writeln ("Player ", num, ": I'm tired of playing!");
      }
      // Otherwise, he agrees with the person who got tired first.
      else {
        notTired = false;
        writeln ("Player ", num, ": Me too!");
      }
    }

    // This while statement makes a choice for each round of the game.
    while notTired.readFF() {
      var rockPaperScissors = chooseBetweenRockPaperScissors();
      if refereeReady(num) && notTired.readFF() then
        writeln ("Player ", num, ": ", rockPaperScissors);
      choice(num) = rockPaperScissors;
    }
  }

  // Once the begin and while statements above finish executing, the player
  // once again agrees with the person who got tired first (which may have been
  // himself).
  writeln ("Player ", num, ": Yeah, me too!");
}

// The following function implements the behavior of the referee.
// There are two components to the behavior: one is to decide who wins
// each round; the other is the attention span the person has.
def referee () {

  // The difference between the cobegin statement here and the sync statement
  // used to implement the behavior of the players is that execution continues
  // past the cobegin statement once each top level statement of the cobegin
  // has been executed.  If any begin statements are encountered inside the
  // cobegin statement (as is the case here), the cobegin statement will not
  // wait for them to finish.
  cobegin {

    begin {
      var delay = RandomNumber() * 10.0 + 3.0;
      sleep (delay : uint);
      // If the referee is the first person to get tired, she so announces.
      if notTired {
        notTired = false;
        writeln ("Referee: I'm tired of playing!");
      }
      // Otherwise, she agrees with the person who got tired first.
      else {
        notTired = false;
        writeln ("Referee: Me too!");
      }
    }

    // This while statement declares the winner for each round of the game.
    while notTired.readFF() {
      var delay = RandomNumber() * 2 + 1.0;
      sleep (delay : uint);

      // Each iteration of the coforall statement launches an
      // independent thread of execution.  As with the cobegin
      // statement, execution continues past the coforall statement
      // when all of its iterations have finished executing; however,
      // as with the cobegin statement, it does not wait for any begin
      // statements it encountered to finish executing.
      coforall i in 1..2 do
        // This tells each player the referee is ready for the next round
        // of the game.  Note that the order in which the players are notified
        // is not guaranteed.
        refereeReady(i) = true;

      // This reads the choice each player made.
      var player1 = choice(1),
          player2 = choice(2);
      determineWinner (player1, player2);
    }
  }

  // Once the while statement above finishes executing and the begin
  // statement is launched, the referee once again agrees with the
  // person who got tired first (which may have been herself).
  // However, note that this writeln will likely not be the last thing
  // this function does!
  writeln ("Referee: Yes, me too!");
}

def RandomNumber() {
  const multiplier: int(64) = 16807,
        modulus: int(64) = 2147483647;
  // The following calculation must be done in at least 46-bit arithmetic!
  var newSeed = (seed * multiplier % modulus) : uint;
  seed = newSeed;
  return (newSeed-1) / (modulus-1) : real;
}

def chooseBetweenRockPaperScissors() {
  var random = RandomNumber();
  var choice = (random * 3.0) : uint + 1;
  return choice : choices;
}

def determineWinner (player1, player2) {
  if player1 == player2 then
    declareWinner("Tied!");
  else if player1 == choices.rock then
    if player2 == choices.paper then
      declareWinner("Player 2 wins!");
    else declareWinner("Player 1 wins!");
  else if player1 == choices.paper then
    if player2 == choices.scissors then
      declareWinner("Player 2 wins!");
    else declareWinner("Player 1 wins!");
  else if player1 == choices.scissors then
    if player2 == choices.rock then
      declareWinner("Player 2 wins!");
    else declareWinner("Player 1 wins!");
}

def declareWinner (w) {
  if notTired.readFF() then
    writeln ("Referee: ", w);
}

// This example illustrates Chapel's parallel tasking features,
// namely the begin, cobegin, coforall, and sync statements,
// as well as sync variables.

// This example is inspired by an imaginary family trip to an out-of-town
// soccer tournament.  It makes use of a random number generator, whose code
// appears near the end of this file.

use Time;
// This initializes the seed used for the random number generator.
var seed: sync uint = getCurrentTime() : uint;

var notThereYet = true;

// The begin statement spawns off a thread of execution that is
// independent from the rest of the program.  In this case, imagine a
// younger member of the family who periodically asks, "Are we there
// yet?" until someone else gets fed up with the incessant questions.

begin
  while notThereYet {
    writeln ("Are we there yet?");
    var delay = RandomNumber() * 4.0;
    sleep (delay : uint);  // wait between 0 and 3 seconds before asking again
  }

// Here's another independent thread of execution.
// When someone (perhaps the father) gets fed up after some period of time,
// he or she gets yells "Shut up!"
begin {
  var delay = RandomNumber() * 8.0 + 5.0;
  sleep (delay : uint);
  notThereYet = false;
  writeln ("Shut up!");
}

// While all the above is going on, some of the siblings decide to play a game
// of rock, paper, scissors.
writeln ("Want to play rock, paper, scissors?");

enum choices {rock, paper, scissors};

// Sync variables are useful for synchronizing between various threads of
// execution.  Besides containing a value, they also can oscillate between an
// empty state and a full state.  Usually, when a sync variable is empty,
// it means it is in the process of being modified, or some thread of execution
// is using some resource associated with this variable.  When this thread of
// execution no longer needs the variable or associated resource, it
// will change the state back to full.  Meanwhile, any other thread of
// execution that wishes to have access to the sync variable is
// blocked until the state of the variable becomes full.

// For the game of rock, paper, scissors, there will be three persons involved,
// represented by three independent threads of execution.  Two people actually
// play the game, while the third person acts as a referee, deciding who wins
// each round of the game.  At some point, one of the three announces he/she is
// tired of playing, at which time all three stop playing.

// This array contains the choice each player makes (rock, paper, or scissors)
// for a given round of the game.  When the state is full, it means
// the associated player has made his/her choice.  When the state is
// empty, it means the referee has seen the choice the player made.
var choice: [1..2] sync choices;

// When full, each element of this array informs the associated player that the
// referee is ready for the next round of the game.
var refereeReady: [1..2] sync bool;

// This variable informs the people involved in the game if someone is tired of
// playing.
var notTired: sync bool = true;

// Each statement of the cobegin statement is an independent thread of
// execution.  In this case, there are three, each corresponding to
// one of the persons involved in the game of rock, paper, scissors.
// Before continuing past a cobegin statement, all threads of
// execution introduced by the cobegin statement must have finished
// execution.  Since this is the last thing in this program, the
// entire program terminates once the game is over, or the person
// stops asking, "Are we there yet?", whichever happens later.
cobegin {
  player(1);
  player(2);
  referee();
}

// The following function implements the behavior of each player.
// There are two components to the behavior: one is to make a choice
// (rock, paper, or scissors) for each round; the other is the
// attention span the person has.
def player(num) {

  // The sync statement is used to introduce synchronization points in
  // a program. Before continuing past a sync statement, all threads
  // of execution that began inside the sync statement must have
  // terminated.  The sync statement is similar to a cobegin
  // statement, but compare how the behavior of the referee is
  // implemented to see how it differs from a cobegin statement.

  sync {

    // This begin statement implements the attention span the player has.
    begin {
      var delay = RandomNumber() * 10.0 + 2.0;
      sleep (delay : uint);
      // If this is the first person to get tired, he announces he's tired.
      if notTired {
        notTired = false;
        writeln ("Player ", num, ": I'm tired of playing!");
      }
      // Otherwise, he agrees with the person who got tired first.
      else {
        notTired = false;
        writeln ("Player ", num, ": Me too!");
      }
    }

    // This while statement makes a choice for each round of the game.
    while notTired.readFF() {
      var rockPaperScissors = chooseBetweenRockPaperScissors();
      if refereeReady(num) && notTired.readFF() then
        writeln ("Player ", num, ": ", rockPaperScissors);
      choice(num) = rockPaperScissors;
    }
  }

  // Once the begin and while statements above finish executing, the player
  // once again agrees with the person who got tired first (which may have been
  // himself).
  writeln ("Player ", num, ": Yeah, me too!");
}

// The following function implements the behavior of the referee.
// There are two components to the behavior: one is to decide who wins
// each round; the other is the attention span the person has.
def referee () {

  // The difference between the cobegin statement here and the sync statement
  // used to implement the behavior of the players is that execution continues
  // past the cobegin statement once each top level statement of the cobegin
  // has been executed.  If any begin statements are encountered inside the
  // cobegin statement (as is the case here), the cobegin statement will not
  // wait for them to finish.
  cobegin {

    begin {
      var delay = RandomNumber() * 10.0 + 2.0;
      sleep (delay : uint);
      // If the referee is the first person to get tired, she so announces.
      if notTired {
        notTired = false;
        writeln ("Referee: I'm tired of playing!");
      }
      // Otherwise, she agrees with the person who got tired first.
      else {
        notTired = false;
        writeln ("Referee: Me too!");
      }
    }

    // This while statement declares the winner for each round of the game.
    while notTired.readFF() {
      var delay = RandomNumber() * 2 + 1.0;
      sleep (delay : uint);

      // Each iteration of the coforall statement launches an
      // independent thread of execution.  As with the cobegin
      // statement, execution continues past the coforall statement
      // when all of its iterations have finished executing; however,
      // as with the cobegin statement, it does not wait for any begin
      // statements it encountered to finish executing.
      coforall i in 1..2 do
        // This tells each player the referee is ready for the next round
        // of the game.  Note that the order in which the players are notified
        // is not guaranteed.
        refereeReady(i) = true;

      // This reads the choice each player made.
      var player1 = choice(1),
          player2 = choice(2);
      determineWinner (player1, player2);
    }
  }

  // Once the while statement above finishes executing and the begin
  // statement is launched, the referee once again agrees with the
  // person who got tired first (which may have been herself).
  // However, note that this writeln will likely not be the last thing
  // this function does!
  writeln ("Referee: Yes, me too!");
}

def RandomNumber() {
  const multiplier: int(64) = 16807,
        modulus: int(64) = 2147483647;
  // The following calculation must be done in at least 46-bit arithmetic!
  var newSeed = (seed * multiplier % modulus) : uint;
  seed = newSeed;
  return (newSeed-1) / (modulus-1) : real;
}

def chooseBetweenRockPaperScissors() {
  var random = RandomNumber();
  var choice = (random * 3.0) : uint + 1;
  return choice : choices;
}

def determineWinner (player1, player2) {
  if player1 == player2 then
    declareWinner("Tied!");
  else if player1 == choices.rock then
    if player2 == choices.paper then
      declareWinner("Player 2 wins!");
    else declareWinner("Player 1 wins!");
  else if player1 == choices.paper then
    if player2 == choices.scissors then
      declareWinner("Player 2 wins!");
    else declareWinner("Player 1 wins!");
  else if player1 == choices.scissors then
    if player2 == choices.rock then
      declareWinner("Player 2 wins!");
    else declareWinner("Player 1 wins!");
}

def declareWinner (w) {
  if notTired.readFF() then
    writeln ("Referee: ", w);
}


Add _defaultOf method for enums.

Add _defaultOf method for enums.

// 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;

// ints, reals, imags
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;

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

// 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));

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;

// ints, reals, imags
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;

// 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;