-
-
Notifications
You must be signed in to change notification settings - Fork 421
Fix issue 2504 - AA.reserve #1929
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1931,6 +1931,7 @@ extern (C) | |
inout(void)[] _aaKeys(inout void* p, in size_t keysize, const TypeInfo tiKeyArray) pure nothrow; | ||
void* _aaRehash(void** pp, in TypeInfo keyti) pure nothrow; | ||
void _aaClear(void* p) pure nothrow; | ||
void _aaReserve(void** p, const TypeInfo_AssociativeArray ti, size_t ndim) pure nothrow; | ||
|
||
// alias _dg_t = extern(D) int delegate(void*); | ||
// int _aaApply(void* aa, size_t keysize, _dg_t dg); | ||
|
@@ -1974,6 +1975,16 @@ void clear(T : Value[Key], Value, Key)(T* aa) | |
_aaClear(*cast(void **) aa); | ||
} | ||
|
||
void reserve(T : Value[Key], Value, Key)(ref T aa, size_t ndim) | ||
{ | ||
_aaReserve(cast(void **)&aa, typeid(Value[Key]), ndim); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, however I used Value[Key] to be consistent with the rest of the file. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are a few kinks we could do better in this area, si @Darredevil let's go with the cleaner way here and we'll update the rest in good time. |
||
} | ||
|
||
void reserve(T : Value[Key], Value, Key)(T* aa, size_t ndim) | ||
{ | ||
reserve(*aa, ndim); | ||
} | ||
|
||
T rehash(T : Value[Key], Value, Key)(T aa) | ||
{ | ||
_aaRehash(cast(void**)&aa, typeid(Value[Key])); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -474,6 +474,23 @@ extern (C) void _aaClear(AA aa) pure nothrow | |
} | ||
} | ||
|
||
/// Reserve AA | ||
extern (C) void _aaReserve(AA* aa, const TypeInfo_AssociativeArray ti, size_t ndim) | ||
{ | ||
ndim = nextpow2(ndim); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The buckets size used should be large enough that if ndim elements are added, the bucket array will not be grown further (ndim function arg value). However, the choices here don't achieve that. Specifically, the bucket array will be grown if it becomes 80% full (GROW_NUM/GROW_DEN). nextpow2(ndim) will not always need this requirement. It will sometimes be necessary to move one power of two further to achieve this. e.g. If the arg is 500, the bucket size selected should be 1024, not 512. I suggest testing for this after the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think applying There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One thing to be cautious of is that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regarding the power-of-two allocation sizes: Best I can tell all the existing bucket allocation code paths use
line is not following it. However, it the power-of-two component is not important, there may be an opportunity with Update: |
||
// lazily alloc implementation | ||
if (aa.impl is null) | ||
aa.impl = new Impl(ti, ndim); | ||
else | ||
{ | ||
if (ndim <= aa.dim) return; | ||
if (aa.used * GROW_DEN > ndim * GROW_NUM) | ||
ndim = (aa.used * GROW_DEN + GROW_NUM - 1) / GROW_NUM; | ||
assert(aa.used * GROW_DEN <= ndim * GROW_NUM); | ||
aa.resize(ndim); | ||
} | ||
} | ||
|
||
/// Rehash AA | ||
extern (C) void* _aaRehash(AA* paa, in TypeInfo keyti) pure nothrow | ||
{ | ||
|
@@ -1013,3 +1030,37 @@ unittest | |
assert(typeid(a).getHash(&a) == typeid(a).getHash(&a)); | ||
assert(typeid(a).getHash(&a) == typeid(a).getHash(&a2)); | ||
} | ||
|
||
// test AA.reserve | ||
unittest | ||
{ | ||
int[int] aa; | ||
assert(aa is null); | ||
|
||
aa.reserve(2000); | ||
assert(aa !is null); | ||
|
||
auto paa = &aa; | ||
paa.reserve(3000); | ||
|
||
foreach(i;0..2000) aa[i] = i; | ||
assert(aa[1337] == 1337); | ||
|
||
// stress test | ||
aa.clear(); | ||
aa.reserve(3_000_000); | ||
|
||
auto impl = (cast(AA*)&aa); | ||
auto buckets = impl.buckets; | ||
|
||
assert(buckets.length >= 2_000_000); | ||
|
||
foreach(i;0..2_000_000) aa[i] = i; | ||
assert(aa[1_999_133] == 1_999_133); | ||
|
||
// pointer should be the same if no rehashing occurs | ||
assert((cast(AA*)&aa).buckets == buckets); | ||
|
||
// try to reserve less than current length | ||
aa.reserve(10); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add an overload for T* as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ouch do we really need this
T*
for new overloads? After all aren't we trying to move away from the ugly C-like pointer syntax?Also while you are at it, note that most AA methods still aren't
@safe
:/There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wilzbach yes, it needs to be there. Otherwise it operates inconsistently with other normal objects that can call "members" based on a pointer.
This is a special case because AA's are builtins. If they were fully library types, this wouldn't be needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sux but ok