Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Add safe Associative Array

Moderators: kris

Posted: 11/01/07 17:24:09

I've had a couple cases now where using string slices from a mutable buffer as keys to an AA causes problems when the buffer contents are changed. Particularly this happens with LineIterator?.

What would be nice is to have an AA that dups the key on first insertion. This prevents the key from being changed. Upon further insertion, the key is not re-inserted, but the value is just changed.

Here is code that does this for any key that is an array:

struct SafeAA(T,U)
{
  T[U] array;
  T opIndex(U key)
  {
    return array[key];
  }

  T opIndexAssign(T value, U key)
  {
    T *cur = key in array;
    if(cur !is null)
      return *cur = value;
    else
      return array[key.dup] = value;
  }

  uint length()
  {
    return array.length;
  }

  void clear()
  {
    array = array.init;
  }

  void remove(U key)
  {
    array.remove(key);
  }

  U[] keys()
  {
    return array.keys;
  }

  //
  // replaces 'in' (is there 'in' operator?)
  //
  T* getref(U key)
  {
    return key in array;
  }

  T[] values()
  {
    return array.values;
  }

  SafeAA!(T,U) rehash()
  {
    array.rehash;
    return *this;
  }

  int opApply(int delegate(ref T key, ref U value) dg)
  {
    int result = 0;
    foreach(k, v; array)
    {
      if((result = dg(k, v)) != 0)
        break;
    }
    return result;
  }

  int opApply(int delegate(ref U value) dg)
  {
    int result = 0;
    foreach(v; array)
    {
      if((result == dg(v)) != 0)
        break;
    }
    return result;
  }
}

The only thing is that the key type has to be an array. If it is a class, then there isn't any consistent way to make a copy of class, so you would have to do something different. If the key is an array of mutable objects, that will also not be safe.

Example code:

  SafeAA!(char[], char[]) map;
  char[] mykey = "hello".dup;
  char[] mykey2 = "hello".dup;
  map[mykey] = "world";
  mykey[0] = 'c';// does not affect key in AA

  map[mykey2] = "world2";
  mykey2[0] = 'c';// does not affect key in AA

  // prints "hello = world2"
  foreach(k, v; map)
    Stdout.format("{} = {}", k, v).newline;

-Steve

There are no responses to display.