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
Move support for API classes #199
Conversation
@@ -54,6 +54,7 @@ | |||
%ignore NS::CLASS::CLASS(Internal*); | |||
%ignore NS::CLASS::CLASS(Internal&); | |||
%ignore NS::CLASS::operator=; | |||
%ignore NS::CLASS::CLASS(CLASS &&); |
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.
Without this change, I get the following error.
Warning 509: Overloaded method Xapian::Document::Document(Xapian::Document const &) effectively ignored,
Warning 509: as it is shadowed by Xapian::Document::Document(Xapian::Document &&).
I don't know much about SWIG. From what's already there, I added this fix. Please tell whether this is the way.
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.
That seems appropriate to me - these objects are reference counted handles, so it's not useful to explicitly wrap ways to create a copy in the target language.
For some reason Tcl needs the copy ctor wrapped. I'm not sure we bothered to work out why, but it shouldn't need the move ctor since it doesn't currently have it.
This includes changes to PositionIterator, PostingIterator, TermIterator and ValueIterator classes. See https://trac.xapian.org/ticket/642
xapian-core/api/positioniterator.cc
Outdated
PositionIterator::PositionIterator(PositionIterator &&) = default; | ||
PositionIterator::PositionIterator(PositionIterator && o) | ||
: internal(o.internal) | ||
{ |
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.
Should I add LOG same as copy ctor & assignment op(except object pointer)?
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 don't think logging is all that useful for these. The compiler is allowed (and sometimes required) to eliminate calls to them, so logging wouldn't correspond to the source exactly anyway.
The only reason I can think that logging might be interesting is to try to find where copies aren't eliminated to try to address that. But by inlining we open things up for the compiler to optimise in more ways, and without the programmer having to study logs. The savings aren't likely to be very large anyway, as copying just copies a pointer and adjusts reference counts.
Overall having these inline in the API headers seems a better trade-off than putting them into the library so they can have debug logging.
Member of iterator class is raw pointer, as a result compiler generated move ctor and assignment leads to memory leak, Hence providing user implementation.
xapian-core/api/positioniterator.cc
Outdated
{ | ||
if (this != &o) | ||
swap(internal, o.internal); | ||
RETURN(*this); |
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.
This should just be return *this;
- only use RETURN
if there's debug logging of the function/method call (i.e. LOGCALL()
or similar).
(These methods aren't really interesting to log, so I think it's fine not to have logging for them.)
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.
Fixed
xapian-core/api/positioniterator.cc
Outdated
: internal(o.internal) | ||
{ | ||
o.internal = nullptr; | ||
} |
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.
This should be OK to have inline in the public API header (include/xapian/positioniterator.h
).
That's beneficial for a trivial implementation like this one as it means that the compiler can inline it and optimise the result. It also means we don't create another external symbol in the shared library (the fewer external symbols there are, the quicker it loads). One extra isn't a big deal by itself, but where they can be easily avoided we try to.
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.
Thanks for the tip. Done.
xapian-core/api/positioniterator.cc
Outdated
PositionIterator::operator=(PositionIterator && o) | ||
{ | ||
if (this != &o) | ||
swap(internal, o.internal); |
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.
This is probably also a candidate for having inline in the public API header (and then the compiler should usually be able to at least optimise away the (this != &o)
check entirely as it can typically see that the two objects are distinct).
If we do that I'm not sure about the use of std::swap()
though - we don't currently pull in <utility>
from public headers and the fewer library headers we include from public headers the better in many ways - user code can end up implicitly relying on our including them so removing them later risks breaking such user code. So perhaps it would be better to write it out in this case (auto t = internal; internal = o.internal; o.internal = t;
).
Or alternatively leave o
with NULL
internals:
if (this != &o) {
if (internal) decref();
internal = o.internal;
o.internal = nullptr;
}
(And similarly for the other iterator classes...)
@@ -29,6 +29,7 @@ | |||
|
|||
#include <iosfwd> | |||
#include <string> | |||
#include <utility> |
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.
Ah, so we'll need <utility>
for std::move
anyway.
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.
We can use static_cast to avoid it. should I go for that?
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.
But I guess it is not a straightforward cast. I have to understand it better first.
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.
Custom impl of move is not trivial it seems. Please ignore my comment.
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.
The cast would be static_cast<PositionIterator&&>(obj)
(when obj
's class is PositionIterator
).
I think that's worse than just including <utility>
though - the code is much clearer using std::move()
.
/// Move constructor. | ||
WritableDatabase(WritableDatabase&& o) : Database(std::move(o)) {} | ||
|
||
/// Move Assignment operator. |
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.
No reason to capitalise "Assignment" here.
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.
Fixed
I think Avoiding including It'd also be good to switch to using
I just looked through the combined diff so far. I really should get on with something else right now, but I'll have a look when I get a chance. |
This is beneficial because compiler can inline it and optimise the result. Also this means, less external symbol in the shared library hence loads quicker.
It is beneficial because compiler can inline it and optimise the result. Also this means, less external symbol in the shared library, so loads quicker. The implementation is chosen to avoid swap so custom swap impl or <utility> header inclusion not required.
It's short, clear and error-safe for default implementation.
Explicitly defaulted function requires return type as reference in function signature.
I think most of the classes in public API covered. Let me know if any other work is pending on this. |
Sorry getting back to this now. The newer changes look good to me, will merge this now.
They look great to me. |
Thanks for all your work on this. |
This PR address ticket #642
I used the
default
keyword for implementation of move ctor and assignment. Currently copy ctor and assignment op have user defined, as it is necessary for pre c++11. I also thought this doesn't require us to include<utility>
to usestd::move
fn(not sure whether this point is really useful). Let me know whether this is fine.Please review when you have time. Thanks!
Can you comment on the commit boundaries I formed? Just curious to know whether I can improve on that.