
$maxrank = 3 ;

@subTypes = ('T', 'S', 'B') ;   # Scalar, triplet or block

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

// Type-secure C++ interface for multi-dimensional arrays.


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
//                                                                     //
// template class `Section_': Adds a data field to `DAD'.              //
//                                                                     //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

template<int R, class T>
class Section_ : public DAD {
public :

  Section_(const Group& _group, T* _data) :
               DAD(R, _group), data(_data) {}

  T* dat() const {return data ; }

  operator IOArg() const {return IOArg((DAD*) this, data, sizeof(T)) ; }
      // Conversion operator to support `aprintf' etc.

protected :
  Section_(const Group& _group) :
               DAD(R, _group) {}
                   // Used by `Array' subclasses.

  Section_() {}  // Used by `SectionR()'

  T* data ;

} ;


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
//                                                                     //
// template classes `SectionR': Add subscripting operations to         //
//                              `Section_'.                            //
//                                                                     //
// template classes `ArrayR': Add element allocation to `SectionR'     //
//                                                                     //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

for($R = 0 ; $R <= $maxrank ; $R++) {

  for($sig = 0 ; $sig < (1 << $R) ; $sig++) {

    # Compute parameters of signature for this instance...

    $numSs = 0 ;
    $mask = 1 ;
    $numSects = 1 ;
    for($r = 0 ; $r < $R ; $r++) {
      if($sig & $mask) {
        $dimType[$r] = 'S' ;
        $numSubs[$r] = 2 ;
        $numSs++ ;
      }
      else {
        $dimType[$r] = 'D' ;
        $numSubs[$r] = 2 ;
        #$numSubs[$r] = 3 ;  # allowing for block subscripts
      }
      $numSects *= $numSubs[$r] ;
      $mask = $mask << 1 ;
    }

    if($numSs) {
      $SIG = join("", @dimType) ;
    }
    else {
      $SIG = "" ;
    }

    ############################################################
    #
    # Section subclass header...
    #
    ############################################################

    if($sig == 0) {  # Signature involves no sequential dimensions
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
template<class T>
class Section$R : public Section_<$R, T> {
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    }
    else {           # Signature involves some sequential dimensions

      if($numSs == 1) {
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
template<class T>
class Section$R$SIG : public virtual Section$R<T> {
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      }
      else {

        # enumerate immediate, non-virtual bases...

        $numBases = 0 ;
        for($r = 0 ; $r < $R ; $r++) {
          if($dimType[$r] eq 'S') {
            if($numSs > 1) {
              $dimType[$r] = 'D' ;
              $BSIG = join("", @dimType) ;
              $dimType[$r] = 'S' ;
            }
            else {
              $BSIG = "" ;
            }
            $bases[$numBases] = "Section$R$BSIG<T>" ;
            $numBases++ ;
          }
        }

        $BASES = &repeat(',\npublic $bases[$r]', "", $numBases) ;

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
template<class T>
class Section$R$SIG : &{private virtual Section$R<T>$BASES&} {
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      }
    }
    
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
public :
  // Constructors

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    ############################################################
    #
    # Section copy constructor
    #
    ############################################################

    if($sig == 0) {  # Signature involves no sequential dimensions

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  Section$R(const Section$R<T>& a) : Section_<$R, T>(a.grp(), a.dat()) {
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      for($r = 0 ; $r < $R ; $r++) {
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    rngs [$r] = a.rng($r) ;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      }
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      for($r = 0 ; $r < $R ; $r++) {
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    strs [$r] = a.jmp($r) ;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      }
      if($R) {
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    DAD :: ranges  = rngs ;
    DAD :: strides = strs ;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      }
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  }

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    }
    else {           # Signature involves some sequential dimensions

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  // (Due to explicit call to constructor for virtual base class,
  //  following constructors are ineffective if invoked from constructor
  //  of derived-class object).

  Section$R$SIG(const Section$R$SIG<T>& a) : Section$R<T>(a) {}

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    }

    ############################################################
    #
    # Section general constructor
    #
    ############################################################

    $RNGS = &repeat('const Range& x_$r,', "\n", $R) . ($R ? " " : "") ;

    $STRS = &repeat('const int str_$r,', "\n", $R) . ($R ? " " : "") ;

    $XS   = &repeat('x_$r,', "\n", $R) . ($R ? " " : "") ;

    $SS   = &repeat('str_$r,', "\n", $R) . ($R ? " " : "") ;

    if($sig == 0) {  # Signature involves no sequential dimensions

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  Section$R(&{${RNGS}const Group& p,
              ${STRS}T* _data&}) : Section_<$R, T>(p, _data) {
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      for($r = 0 ; $r < $R ; $r++) {
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    rngs [$r] = x_$r ;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      }
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      for($r = 0 ; $r < $R ; $r++) {
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    strs [$r] = str_$r ;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      }
      if($R) {
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    DAD :: ranges  = rngs ;
    DAD :: strides = strs ;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      }
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  }

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    }
    else {           # Signature involves some sequential dimensions

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  Section$R$SIG(&{${RNGS}const Group& p,
                  ${STRS}T* _data&}) : Section$R<T>(&{${XS}p,
                                                      ${SS}_data) {}

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    }

    ############################################################
    #
    # Simple subscripting operator
    #
    ############################################################

    for($r = 0 ; $r < $R ; $r++) {
      if($dimType[$r] eq 'D') {
        $args[$r] = "const Location& i_$r" ;
        $offs[$r] = "str($r).offset(i_$r)" ;
      }
      else {
        $args[$r] = "const int i_$r" ;
        $offs[$r] = "str($r).offset(rng($r)(i_$r))" ;
      }
    }

    $ARGS = &repeat('$args[$r]', ",\n", $R) ;

    $OFFS = $R ? &repeat('$offs[$r]', " +\n", $R) : "0" ;

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  // Simple subscripting

  T& operator()(&{$ARGS&}) const {
    return dat() [&{$OFFS&}] ;
  }

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    ############################################################
    #
    # Section subscripting methods
    #
    ############################################################

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  // Section subscripting

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    for($sect = 0 ; $sect < $numSects ; $sect++) {

      # Compute `sect' argument types for this instance...

      $residue = $sect ;
      for($r = 0 ; $r < $R ; $r++) {
        $subType[$r] = $subTypes[$residue % $numSubs[$r]] ;
        $residue /= $numSubs[$r] ;
      }

      # Compute result type...

      $resR     = 0 ;
      $resNumSs = 0 ;
      for($r = 0 ; $r < $R ; $r++) {
        if($subType[$r] eq 'T') {
          $resDimType[$resR] = $dimType[$r] ;
          if($dimType[$r] eq 'S') {
            $resNumSs++ ;
          }
          $resR++ ;
        }
      }

      if($resNumSs) {
        $resSIG = join("", @resDimType[0 .. $resR - 1]) ;
      }
      else {
        $resSIG = "" ;
      }

      # Print section member...
      
      $t = 0 ;
      $s = 0 ;
      $d = 0 ;
      for($r = 0 ; $r < $R ; $r++) {
        if($subType[$r] eq 'T') {
          $args[$r] = "const Trip& i_$r" ;
          $rngs[$t] = "rng($r)(i_$r)" ;
          $strs[$t] = "jmp($r)" ;
          $t++ ;
        }
        if($subType[$r] eq 'S') {
          if($dimType[$r] eq 'D') {
            $args[$r] = "const Location& i_$r" ;
            $divs[$d] = "i_$r" ;
            $offs[$s] = "str($r).offset(i_$r)" ;
            $d++ ;
          }
          else {
            $args[$r] = "const int i_$r" ;
            $offs[$s] = "str($r).offset(rng($r)(i_$r))" ;
          }
          $s++ ;
        }
      }

      $ARGS = &repeat('$args[$r]', ",\n", $R) ;

      $RNGS = &repeat('$rngs[$r]', ",\n", $t) . ($t ? ", " : "") ;

      $DIVS = &repeat(' / $divs[$r]', "", $d) ;

      $STRS = &repeat('$strs[$r]', ",\n", $t) . ($t ? ", " : "") ;

      $OFFS = ($s ? " " : "") . "&{" . &repeat('+ $offs[$r]', "\n", $s) . "&}" ;

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  Section$resR$resSIG<T> sect(&{$ARGS&}) const {
    return Section$resR$resSIG<T>(&{${RNGS}grp()$DIVS,
                                    ${STRS}dat()$OFFS&}) ;
  }

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    }
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
protected :
  Section$R$SIG() {}  // Used by subclasses.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    if($sig == 0) {  # Signature involves no sequential dimensions
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

  Section$R(const Group& p) : Section_<$R, T>(p) {
      // Used by Array classes to initialize virtual base.

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      
      if($R) {
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    DAD :: ranges  = rngs ;
    DAD :: strides = strs ;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      }
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  }

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      if($R) {
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  Range rngs [$R] ;
  int   strs [$R] ;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      }
    }
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
} ;


>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    ############################################################
    #
    # Print Array subclass header...
    #
    ############################################################

    if($sig == 0) {  # Signature involves no sequential dimensions
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
template<class T>
class Array$R : public Section$R<T> {
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    }
    else {           # Signature involves some sequential dimensions
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
template<class T>
class Array$R$SIG : public Section$R$SIG<T>, private virtual Section$R<T> {
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    }

    ############################################################
    #
    # Array general constructor
    #
    ############################################################

    for($r = 0 ; $r < $R ; $r++) {
      if($dimType[$r] eq 'D') {
        $args [$r] = "const Range& x_$r" ;
        $rngs [$r] = <<EOF ;
    rngs [$r] = x_$r ;
EOF
        $strs [$r] = <<EOF ;
    strs [$r] = size ;
    size *= x_$r.volume() ;
EOF
      }
      else {
        $args [$r] = "const int n_$r" ;
        $rngs [$r] = <<EOF ;
    rngs [$r] = n_$r ;
EOF
        $strs [$r] = <<EOF ;
    strs [$r] = size ;
    size *= n_$r ;
EOF
      }
    }

    $ARGS = &repeat('$args[$r],', "\n", $R) . ($R ? " " : "") ;

    $RNGS = ($R ? "\n" : "") . &repeat('$rngs[$r]', "", $R) ;

    $STRS = &repeat('$strs[$r]', "", $R) ;

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
public:

  Array$R$SIG(&{${ARGS}const Group& p = apg&}) : Section$R<T>(p) {
$RNGS    
    int size = 1 ;
$STRS
    data = new T [size] ;
  }

  ~Array$R$SIG() {
    delete [] data ;
  }

private :
  Array$R$SIG(const Array$R$SIG& a) : Section$R$SIG(a) {}  // Prohibit copying.

} ;

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  }
}

# ---------------------------------------------------------------
#
# Things to do:
#
#   The `sect' members aren't exactly right.  Actually it should be possible
#   to use `const int' section subscripts even in distributed dimensions.

