Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive

_equals druntime template for structs#1792

Merged
dlang-bot merged 1 commit intodlang:masterfrom
somzzz:arrayEq
Mar 15, 2017
Merged

_equals druntime template for structs#1792
dlang-bot merged 1 commit intodlang:masterfrom
somzzz:arrayEq

Conversation

@somzzz
Copy link
Contributor

@somzzz somzzz commented Mar 15, 2017

This is similar to what happened to adCmp, or __cmp, only that it's a first step, rather than the whole implementation. This is the template function for testing equality on arrays of structs (basetype is struct).

I also worked on a dmd patch lowering EqualExp to this code for arrays of structs. Locally, Druntime and Phobos tests are passing with the new implementation.

__equals is a bit more interesting than __cmp because for arrays of basic types the compiler makes an optimization and generates a call too "memcmp" directly rather than call a druntime function. See here: https://github.com/dlang/dmd/blob/master/src/ddmd/e2ir.d#L2282

I avoided changing that bit for the time being until we can agree on what the best approach is. This is one of the reasons this PR only does struct array comparisons. The other would be that a smaller PR is easier to review.

src/object.d Outdated
bool __equals(T1, T2)(T1[] lhs, T2[] rhs)
{
if (lhs.length != rhs.length)
return 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stylistic nitpick: if you're going to use return true; at the end, then make this return false;

enum RTInfo = null;
}

bool __equals(T1, T2)(T1[] lhs, T2[] rhs)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment before this function a la // lhs == rhs lowers to __equals(lhs, rhs) for arrays of all struct types.

src/object.d Outdated
import core.internal.traits : Unqual;
alias U1 = Unqual!T1;
alias U2 = Unqual!T2;
static assert(is(U1 == U2), "Internal error.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to define names because we're never using them, static assert(is(Unqual!T1 == Unqual!T2), "Internal error."); should suffice

src/object.d Outdated
foreach (const u; 0 .. lhs.length)
{
auto s1 = at(lhs, u);
auto s2 = at(rhs, u);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't create temporaries here, just invoke at inline; the structs may not be copyable

src/object.d Outdated

static if (__traits(compiles, s1.opEquals(s2)))
{
auto result = (s1).opEquals(s2);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for parens around s1

src/object.d Outdated
}
else
{
return s1.tupleof == s2.tupleof;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (s1.tupleof != s2.tupleof)
    return false;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should write a unittest that fails with the current code and passes with the correct one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand what you mean here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nvm, got it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. I had a case where both assert(a != b); and assert(a==b); passed with that code because I forgot to do this in the compiler:

                if (op == TOKnotequal)
                {
                    __equals = new NotExp(loc, __equals);
                }

src/object.d Outdated
{
auto result = (s1).opEquals(s2);
if (!result)
return result;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit much pomp and circumstance. This should be enough:

if (!s1.opEquals(s2))
    return false;

src/object.d Outdated
}
else
{
if(!(at(lhs, u).tupleof == at(rhs, u).tupleof))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. Did != not work?


assert(arr1 != arr2);
assert(arr2 == arr3);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to also add a unittest for a struct that defines opEquals for coverage.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants