New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make std.array.insertInPlace @safe for some cases #1430
Conversation
I'm getting a little weary of these safety tricks that Kenji introduced but are now becoming more prevalent. Are we going to keep spamming lambda functions everywhere just to simulate safety? It really feels like the wrong approach. Using this lambda trick also introduced a regression, so it has some issues with scoping. (although maybe that's just a compiler bug). @andralex: Any opinions about these lambdas recently? Or am I worrying too much? |
I agree. What's the point of even having |
Are you complaining about the fact that we have functions that are safe that weren't before? Or the "hackish" approach of doing it via lambdas ? I suggested a little while ago, doing the same thing with a more idiomatic "blocks with attributes".
Isn't that what |
Currently there is a performance issue to use trusted lambda call and 9rnsr proposed a pull request to solve this issue (See Issue 2483 in dmd: dlang/dmd#2483). Can I wait for issue 2483 merged or use nested functions instead of lambda call? |
I think the implementation is way too lacking to be able to promise safety. If one of the calls to emplace throws, then the passed in slice will be modified to contain elements that were duplicated, but without a call to postblit, which can later lead to very nasty some very memory corruption issues. You could fix this by making a temp slice, and only assign back to the original slice at the end of the operation. Such a fix would be necessary. Also, as I mentioned in I suggest you change the pointer iteration for simple index iteration. This means the only line of code that would be unsafe is |
Sorry for late reply.
I found several things for that.
First, I will make |
I filed one bug in druntime (Bugzilla: http://d.puremagic.com/issues/show_bug.cgi?id=11041). |
You can usually "bypass" these kinds of problem with "if (__ctfe)", where you "run" simpler code in case of ctfe. Further more, you should mostly consider simplicity over efficiency for ctfe (after all, the code is never "run"). Bypassing "move" entirelly in copy backwards should be fine. |
Thank you for your advice. BTW, should struct T
{
int a;
@disable typeof(this) opAssign(typeof(this));
}
T[] a = [ T(1), T(2), T(3), T(4) ];
a.insertInPlace(2, [ T(1), T(2) ]);
assert(a == [ T(1), T(2), T(1), T(2), T(3), T(4) ]); |
@AndrejMitrovic: Regarding |
Now Some notes:
|
@@ -897,20 +917,24 @@ void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff) | |||
to_insert += stuff[i].length; | |||
} | |||
array.length += to_insert; | |||
copyBackwards(array[pos..oldLen], array[pos+to_insert..$]); | |||
auto ptr = array.ptr + pos; | |||
auto tmp = new T[to_insert]; |
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.
Wait, why the extra GC allocation? Or am I missing something (just looking at the diff right now)?
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.
I think it's a "quick and dirty" way to achieve strong exception safety: If one of the insertions go wrong, then the original range is never modified.
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.
In which case, that array.length
should but moved down...
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.
BTW, when allocating a temp array/buffer like this, you are usually better of using uninitializedArray
(or minimallyInitilaizedArray
).
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.
Thank you for your comments and advice.
I moved down array.length
and now insertInPlace
uses uninitializedArray
to allocate buffer.
Looking better :) |
If there are no problem, I will squash the commits. |
Looks good. Indeed, please squash. |
I squashed the commits. |
Oh... |
Done. |
Make std.array.insertInPlace @safe for some cases
Merged. TYVM. |
This pull request makes
insertInPlace
safe for some cases like:int[]
I leave the case for strings because the unittest for it uses
std.conv.to
which is currently not safe for strings.