August 31, 2005
This is no doubt been posted but I thought I would post it anyhow.

Often you have a class which basically adds functionality over a map or array.  These two mixins implement the opApply/opIndex functions for you.

//// THE CODE ==================

template applyThis( V, alias var )
{
  public int opApply( int delegate( inout V val ) dg )
  {
    int n = 0;
    foreach( V val; var ) { n = dg(val); if (n) break; }
    return n;
  }
  public int opApply( int delegate( inout int index, inout V val ) dg )
  {
    int n = 0;
    foreach( int index, V val; var ) { n = dg(index,val); if (n) break; }
    return n;
  }
  public V opIndex( int index )
  {
    if ( index<=var.length ) return V.init;
    return var[index];
  }
  public V opIndexAssign( V val, int index )
  {
    if ( var.length<=index ) var.length = index+1;
    return var[index] = val;
  }
}

template applyThis( K, V, alias var )
{
  public int opApply( int delegate( inout K key, inout V val ) dg )
  {
    int n = 0;
    foreach( K key, V val; var ) { n = dg(key,val); if (n) break; }
    return n;
  }

  public V opIndex( K key )
  {
    V* ptr = (key in var);
    if ( ptr is null ) return V.init;
    else return ptr[0];
  }

  public V opIndexAssign( V val, K key )
  {
    return var[key] = val;
  }
}



///  Example: ==================
class MyWidgets
{
  Widget[]		widgets;
  Widget[char[]]	lookup;

  //... other useful stuff
  mixin applyThis!( Widget, widgets );
  mixin applyThis!( char[], Widget, lookup );
}

-DavidM
September 01, 2005
David Medlock escribió:
> This is no doubt been posted but I thought I would post it anyhow.
> 
> Often you have a class which basically adds functionality over a map or array.  These two mixins implement the opApply/opIndex functions for you.
> 
> //// THE CODE ==================
> 
> template applyThis( V, alias var )
> {
>   public int opApply( int delegate( inout V val ) dg )
>   {
>     int n = 0;
>     foreach( V val; var ) { n = dg(val); if (n) break; }
>     return n;
>   }
>   public int opApply( int delegate( inout int index, inout V val ) dg )
>   {
>     int n = 0;
>     foreach( int index, V val; var ) { n = dg(index,val); if (n) break; }
>     return n;
>   }
>   public V opIndex( int index )
>   {
>     if ( index<=var.length ) return V.init;
>     return var[index];
>   }
>   public V opIndexAssign( V val, int index )
>   {
>     if ( var.length<=index ) var.length = index+1;
>     return var[index] = val;
>   }
> }
> 
> template applyThis( K, V, alias var )
> {
>   public int opApply( int delegate( inout K key, inout V val ) dg )
>   {
>     int n = 0;
>     foreach( K key, V val; var ) { n = dg(key,val); if (n) break; }
>     return n;
>   }
> 
>   public V opIndex( K key )
>   {
>     V* ptr = (key in var);
>     if ( ptr is null ) return V.init;
>     else return ptr[0];
>   }
> 
>   public V opIndexAssign( V val, K key )
>   {
>     return var[key] = val;
>   }
> }
> 
> 
> 
> ///  Example: ==================
> class MyWidgets
> {
>   Widget[]        widgets;
>   Widget[char[]]    lookup;
> 
>   //... other useful stuff
>   mixin applyThis!( Widget, widgets );
>   mixin applyThis!( char[], Widget, lookup );
> }
> 
> -DavidM

Funny: I defined a couple of similar mixins for my project, except that I didn't define opIndex nor opIndexAssign.

This solution has a problem when you need opApply for more than one collection. Eg:

class MyWidgets
{
   Widget[]        widgets;
   Widget[char[]]    lookup;
   Property[char[]] properties; //or whatever you want

   //... other useful stuff
   mixin applyThis!( Widget, widgets );
   mixin applyThis!( char[], Widget, lookup );
   mixin applyThis!( char[], Property, properties );
}

The compiler won't let you do that, so you have to do:

   mixin applyThis!( Widget, widgets ) foo1;
   mixin applyThis!( char[], Widget, lookup ) foo2;
   mixin applyThis!( char[], Property, properties ) foo3;
   alias foo1.opApply opApply;
   alias foo2.opApply opApply;
   ...

It's the only downside.

-- 
Carlos Santander Bernal