Showing with 93 additions and 0 deletions.
  1. +28 −0 src/object.di
  2. +65 −0 src/object_.d
28 changes: 28 additions & 0 deletions src/object.di
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,34 @@ Value[] values(T : Value[Key], Value, Key)(T *aa) @property
return (*aa).values;
}

auto byKeyValue(T : Value[Key], Value, Key)(T aa) pure nothrow @nogc @property
{
static struct Result
{
AARange r;

pure nothrow @nogc:
@property bool empty() { return _aaRangeEmpty(r); }
@property auto front() @trusted
{
static struct Pair
{
private Key* keyp;
private Value* valp;

@property ref Key key() { return *keyp; }
@property ref Value value() { return *valp; }
}
return Pair(cast(Key*)_aaRangeFrontKey(r),
cast(Value*)_aaRangeFrontValue(r));
}
void popFront() { _aaRangePopFront(r); }
Result save() { return this; }
}

return Result(_aaRange(p));
}

inout(V) get(K, V)(inout(V[K]) aa, K key, lazy inout(V) defaultValue)
{
auto p = key in aa;
Expand Down
65 changes: 65 additions & 0 deletions src/object_.d
Original file line number Diff line number Diff line change
Expand Up @@ -2125,6 +2125,36 @@ Value[] values(T : Value[Key], Value, Key)(T *aa) @property
return (*aa).values;
}

auto byKeyValue(T : Value[Key], Value, Key)(T aa) pure nothrow @nogc @property
{
static struct Result
{
AARange r;

pure nothrow @nogc:
@property bool empty() { return _aaRangeEmpty(r); }
@property auto front() @trusted
{
static struct Pair
{
// We save the pointers here so that the Pair we return
// won't mutate when Result.popFront is called afterwards.
private Key* keyp;
private Value* valp;

@property ref Key key() { return *keyp; }
@property ref Value value() { return *valp; }
}
return Pair(cast(Key*)_aaRangeFrontKey(r),
cast(Value*)_aaRangeFrontValue(r));
}
void popFront() { _aaRangePopFront(r); }
Result save() { return this; }
}

return Result(_aaRange(cast(void*)aa));
}

inout(V) get(K, V)(inout(V[K]) aa, K key, lazy inout(V) defaultValue)
{
auto p = key in aa;
Expand Down Expand Up @@ -2354,6 +2384,41 @@ pure nothrow unittest
//testFwdRange(aa.byPair, tuple("a", 1));
}

unittest
{
// Issue 9119
int[string] aa;
assert(aa.byKeyValue.empty);

aa["a"] = 1;
aa["b"] = 2;
aa["c"] = 3;

auto pairs = aa.byKeyValue;

auto savedPairs = pairs.save;
size_t count = 0;
while (!pairs.empty)
{
assert(pairs.front.key in aa);
assert(pairs.front.value == aa[pairs.front.key]);
count++;
pairs.popFront();
}
assert(count == aa.length);

// Verify that saved range can iterate over the AA again
count = 0;
while (!savedPairs.empty)
{
assert(savedPairs.front.key in aa);
assert(savedPairs.front.value == aa[savedPairs.front.key]);
count++;
savedPairs.popFront();
}
assert(count == aa.length);
}

// Explicitly undocumented. It will be removed in March 2015.
deprecated("Please use destroy instead of clear.")
alias destroy clear;
Expand Down