Closed Bug 1490781 Opened 6 years ago Closed 5 years ago

Add FunctionRef - a non-owning reference to a Callable

Categories

(Core :: MFBT, enhancement)

63 Branch
enhancement
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla76
Tracking Status
firefox76 --- fixed

People

(Reporter: jrmuizel, Assigned: fronkc1, Mentored)

References

Details

(Keywords: good-first-bug, Whiteboard: [gfx-noted] [lang=c++])

Attachments

(2 files, 7 obsolete files)

Here's LLVM's implementation: /// An efficient, type-erasing, non-owning reference to a callable. This is /// intended for use as the type of a function parameter that is not used /// after the function in question returns. /// /// This class does not own the callable, so it is not in general safe to store /// a function_ref. template<typename Fn> class function_ref; template<typename Ret, typename ...Params> class function_ref<Ret(Params...)> { Ret (*callback)(intptr_t callable, Params ...params) = nullptr; intptr_t callable; template<typename Callable> static Ret callback_fn(intptr_t callable, Params ...params) { return (*reinterpret_cast<Callable*>(callable))( std::forward<Params>(params)...); } public: function_ref() = default; function_ref(std::nullptr_t) {} template <typename Callable> function_ref(Callable &&callable, typename std::enable_if< !std::is_same<typename std::remove_reference<Callable>::type, function_ref>::value>::type * = nullptr) : callback(callback_fn<typename std::remove_reference<Callable>::type>), callable(reinterpret_cast<intptr_t>(&callable)) {} Ret operator()(Params ...params) const { return callback(callable, std::forward<Params>(params)...); } operator bool() const { return callback; } };
It should be quite straightforward to port this implementation to MFBT. Should make a good mentored bug, maybe even a good first bug for someone who has experience with C++ (i.e. if the code in comment 1 doesn't scare you, this should be totally doable even if this is your first Mozilla bug).
Mentor: botond
Keywords: good-first-bug
Whiteboard: [gfx-noted] [lang=c++]
:botond Can I take this bug? I have to port above implementation to MFBT. I am currently looking at this https://developer.mozilla.org/en-US/docs/Mozilla/MFBT and any other help would be much appreciated :)
Flags: needinfo?(botond)
Thanks for your interest! I see you've already fixed a bug that involved changes to C++ code, so I assume you already have a local build handy. The general idea is: - Create a new header mfbt/FunctionRef.h - Copy the code from comment 1 into it, making two kinds of modifications: (1) Use MFBT type traits instead of standard type traits. std::enable_if, std::is_same, ands std::remove_reference all have MFBT equivalents. (2) Use Mozilla coding style (formatting and naming). The Mozilla style guide can be found here [1]. - Be sure to give FunctionRef.h a copyright header and an include guard (see other headers in mfbt/ for examples). - Add the new header to mfbt/moz.build, under EXPORTS.mozilla. (This will allow us to include the new header as "mozilla/FunctionRef.h" from anywhere in the codebase.) - Make sure the codebase builds with your changes. Once you've done that, please submit a patch containing your changes for review. As a follow-up, if you're interested, we can add a small test suite for the new class. [1] https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Coding_Style
Flags: needinfo?(botond)
Attached patch Bug1490781.patch (obsolete) — Splinter Review
Attachment #9008952 - Flags: review?(botond)
:botond I am interested in adding a test suite and looking into some existing tests in mfbt/tests to get some idea. Let me know what can I look into further.
Flags: needinfo?(botond)
(In reply to Anushi Maheshwari[:Anushi1998] from comment #5) > Created attachment 9008952 [details] [diff] [review] > Bug1490781.patch You forgot to add the header file to the patch! :-) To do that, run `hg add mfbt/FunctionRef.h`, then `hg amend` (or `hg commit --amend`), and attach the updated patch here again. Thanks.
Assignee: nobody → anushimaheshwari95
Flags: needinfo?(anushimaheshwari95)
Attached patch Bug1490781.patch (obsolete) — Splinter Review
Attachment #9008952 - Attachment is obsolete: true
Attachment #9008952 - Flags: review?(botond)
Flags: needinfo?(anushimaheshwari95)
Attachment #9008972 - Flags: review?(botond)
Comment on attachment 9008972 [details] [diff] [review] Bug1490781.patch Review of attachment 9008972 [details] [diff] [review]: ----------------------------------------------------------------- ::: mfbt/FunctionRef.h @@ +3,5 @@ > +/* This Source Code Form is subject to the terms of the Mozilla Public > + * License, v. 2.0. If a copy of the MPL was not distributed with this > + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ > + > +/* Represents the native path format on the platform. */ This comment looks like it came from a different file.
Am I not supposed to include copyright header?
Flags: needinfo?(jmuizelaar)
(In reply to Anushi Maheshwari[:Anushi1998] from comment #10) > Am I not supposed to include copyright header? The copyright header is fine. However, you copied a second comment that was underneath the copyright header: /* Represents the native path format on the platform. */ This comment is specific to the file it came from (Path.h).
Flags: needinfo?(jmuizelaar)
Comment on attachment 9008972 [details] [diff] [review] Bug1490781.patch Review of attachment 9008972 [details] [diff] [review]: ----------------------------------------------------------------- Thanks, this looks good! A few minor formatting nits: ::: mfbt/FunctionRef.h @@ +11,5 @@ > + > +#include "mozilla/TypeTraits.h" > + > +/** > +*An efficient, type-erasing, non-owning reference to a callable. This is Please add a space between the star and the subsequent word. @@ +19,5 @@ > +*a function_ref. > +*/ > +template<typename Fn> class function_ref; > + > +template<typename Ret, typename ...Params> The convention in this codebase is to put the space after the ... @@ +35,5 @@ > + function_ref() = default; > + function_ref(std::nullptr_t) {} > + > + template <typename Callable> > + function_ref(Callable &&callable, Likewise for &&, space goes after
Attachment #9008972 - Flags: review?(botond) → feedback+
Comment on attachment 9008972 [details] [diff] [review] Bug1490781.patch Review of attachment 9008972 [details] [diff] [review]: ----------------------------------------------------------------- ::: mfbt/FunctionRef.h @@ +8,5 @@ > + > +#ifndef mozilla_FunctionRef_h > +#define mozilla_FunctionRef_h > + > +#include "mozilla/TypeTraits.h" We should also include <cstddef> for std::nullptr_t, and <utility> for std::forward. (Even though mozilla/TypeTraits.h likely already includes both of those, we try to practice "include what you use" to avoid implicit dependencies on headers that could break code during refactoring.) If you're wondering where I got those headers from, I looked up std::nullptr_t [1] and std::forward [2] on cppreference.com; those pages document what headers they are declared in. [1] https://en.cppreference.com/w/cpp/types/nullptr_t [2] https://en.cppreference.com/w/cpp/utility/forward
(In reply to Anushi Maheshwari[:Anushi1998] from comment #6) > :botond I am interested in adding a test suite and looking into some > existing tests in mfbt/tests to get some idea. Let me know what can I look > into further. Great, thanks! You can have a look at this old patch, where I added some tests for an earlier mozilla::Function utility (which has since been removed in favour of std::function): https://hg.mozilla.org/mozilla-central/rev/a95aa5247675 We could add a similar test for mozilla::FunctionRef. (Not all test cases may be applicable to FunctionRef, but a lot of them should be.)
Flags: needinfo?(botond)
Attached patch Bug1490781.patch (obsolete) — Splinter Review
Apologies for the delay. I was hospitalized yesterday :(
Attachment #9008972 - Attachment is obsolete: true
Attachment #9009425 - Flags: review?(botond)
Comment on attachment 9009425 [details] [diff] [review] Bug1490781.patch Review of attachment 9009425 [details] [diff] [review]: ----------------------------------------------------------------- Thanks for the update! ::: mfbt/FunctionRef.h @@ +6,5 @@ > + > +#ifndef mozilla_FunctionRef_h > +#define mozilla_FunctionRef_h > + > +#include <cstdef> The header name is <cstddef>, with two d's. (It's short for "C standard definitions".) On a related note, so far we don't have anything that includes this header (FunctionRef.h) and tries to compile it. We should probably wait until the tests are also written before landing this, so that we have something exercising this code. @@ +20,5 @@ > +* a function_ref. > +*/ > +template<typename Fn> class function_ref; > + > +template<typename Ret, typename ... Params> Sorry, I should have been more clear: the convention is to put a space after the "...", and not before. That applies in several places below as well (e.g. "Params ...params"). @@ +36,5 @@ > + function_ref() = default; > + function_ref(std::nullptr_t) {} > + > + template <typename Callable> > + function_ref(Callable && callable, Likewise here, space after the "&&", and not before.
Attachment #9009425 - Flags: review?(botond)
Attached patch Bug1490781.patch (obsolete) — Splinter Review
All of the tests of `Function.h` were passing when I run `.mach build faster`. Also, how can I run specific test of mfbt?
Attachment #9009425 - Attachment is obsolete: true
Flags: needinfo?(botond)
Attachment #9010122 - Flags: review?(botond)
(In reply to Anushi Maheshwari[:Anushi1998] from comment #17) > All of the tests of `Function.h` were passing when I run `.mach build > faster`. |mach build faster| does not actually compile C++ code; it's for building after changes to front-end (JS and CSS) code only. Please try building the patch with |mach build|. When I try that, I get a number of compiler errors, the first one being: FunctionRef.h:7:2: error: unterminated conditional directive #ifndef mozilla_FunctionRef_h ^
Flags: needinfo?(botond)
Attachment #9010122 - Flags: review?(botond)
(In reply to Anushi Maheshwari[:Anushi1998] from comment #17) > Also, how can I run specific test of mfbt? You can run the test executable in the object directory, e.g. <objdir>/mfbt/tests/TestFunctionRef, where <objdir> is your object directory. By default, the object directory is a subdirectory of the source directory whose name starts with "obj-", e.g. for me it's "obj-x86_64-pc-linux-gnu". There may be a |mach| command for running the test too, but I don't know what it is.
(Anushi, I saw you tried to contact me on IRC; sorry I missed your message. Please try the #apz channel rather than a private message next time. You're also welcome to ask in #developers, and other people may be able to help you even if I'm not around.)
:botond Sure, no worries. I will ask on the public channel next time :)
Hey Anushi, just wondering how things are going here. Anything I can help with?
Flags: needinfo?(anushimaheshwari95)
Attached patch Bug1490781.patch (obsolete) — Splinter Review
Apologies for delay. I have removed capturing lambda Tests, let me know if we can include them :)
Attachment #9010122 - Attachment is obsolete: true
Flags: needinfo?(anushimaheshwari95) → needinfo?(botond)
Attachment #9016125 - Flags: review?(botond)
Comment on attachment 9016125 [details] [diff] [review] Bug1490781.patch Review of attachment 9016125 [details] [diff] [review]: ----------------------------------------------------------------- ::: mfbt/FunctionRef.h @@ +4,5 @@ > + * License, v. 2.0. If a copy of the MPL was not distributed with this > + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ > + > +// #ifndef mozilla_FunctionRef_h > +// #define mozilla_FunctionRef_h The include guard is important. Please uncomment it. The reason it was giving a compiler error (which is presumably why you commented it) is that the #endif directive at the end of the file is missing.
Attachment #9016125 - Flags: review?(botond)
(In reply to Anushi Maheshwari[:Anushi1998] from comment #23) > I have removed capturing lambda Tests, let me know if we can include them :) Why did you remove them? Did something fail / break when you included them?
Flags: needinfo?(botond)
I pushed the patch to our Try server to see that it's building (and the test is passing) on all platforms: https://treeherder.mozilla.org/#/jobs?repo=try&revision=bbf5e8bdecec29d7dab424d9b422e8f4d79ec3e8
(In reply to Botond Ballo [:botond] from comment #26) > I pushed the patch to our Try server to see that it's building (and the test > is passing) on all platforms: > > https://treeherder.mozilla.org/#/ > jobs?repo=try&revision=bbf5e8bdecec29d7dab424d9b422e8f4d79ec3e8 The Try push is showing builds failing due to errors produced by our static analysis plugin. Our static analysis plugin is a compiler plugin that performs additional checks that the compiler itself does not. There are three errors: > FunctionRef.h:37:3: error: bad implicit conversion constructor for 'function_ref' This is complaining about the fact that having a one-argument constructor that's not marked |explicit| allows implicit conversions to function_ref from the argument type(s) the constructor accepts. As unintended implicit conversions can be undesirable and lead to subtle bugs, we have a policy where one-argument constructors need to either be marked |explicit|, or be annotated with the macro |MOZ_IMPLICIT|, which tells the compiler plugin "this is deliberately an implicit constructor". In this case, implicitly converting a compatible callable object to function_ref is reasonable, and matches what both std::function [1] and the proposed std::function_ref [2] do, so we should go ahead and mark the constructor |MOZ_IMPLICIT|. > FunctionRef.h:40:3: error: bad implicit conversion constructor for 'function_ref' This is the same error for the other one-argument constructor of function_ref. > FunctionRef.h:51:3: error: bad implicit conversion operator for 'function_ref<int (int)>' This is a similar error for function_ref's operator bool, given for a similar reason. std::function's operator bool is explicit [1], while the proposed specification of std::function_ref currently doesn't have an operator bool (which is probably just an omission). I suggest we follow std::function's lead here too, and make our operator bool |explicit|. [1] https://en.cppreference.com/w/cpp/utility/functional/function/operator_bool [1] https://en.cppreference.com/w/cpp/utility/functional/function/function [2] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0792r2.html#specification
There is one other issue: as I recently discovered (bug 1498767), adding new MFBT tests to mfbt/tests/moz.build is not sufficient to get them to run in our automation. They also need to be added to another file, testing/cppunittest.ini [1]. [1] https://searchfox.org/mozilla-central/source/testing/cppunittest.ini
Attached patch Bug1490781.patchSplinter Review
It's weird I was trying g (in capturing lambda) to be a pointer and I didn't even notice that :/
Attachment #9016125 - Attachment is obsolete: true
Attachment #9016916 - Flags: review?(botond)
Comment on attachment 9016916 [details] [diff] [review] Bug1490781.patch Review of attachment 9016916 [details] [diff] [review]: ----------------------------------------------------------------- Thanks for the updated patch. The issues discussed in comment 27 and comment 28 remain to be addressed.
Attachment #9016916 - Flags: review?(botond)
Hey Anushi, are you planning to continue working on this?
Flags: needinfo?(anushimaheshwari95)
As we have not heard from Anushi in a while, I'm going to make this bug available for others to work on.
Assignee: anushimaheshwari95 → nobody
Flags: needinfo?(anushimaheshwari95)
HI there Botond i am an undergrad student in engineering,looking forward to make contribution. I went through comments and i am working on the patch I have added the header file and cppunittest.ini next what should i add ?
(In reply to shivambalikondwar from comment #33) > HI there Botond > i am an undergrad student in engineering,looking forward to make > contribution. Hi, thanks for your interest! > I went through comments and i am working on the patch > I have added the header file and cppunittest.ini > next what should i add ? I assume you've built the Firefox codebase before? Please build with the patch applied, and run the test as described in comment 19. If it builds successfully and the test run passes, you can go ahead and submit the patch for review. (I see you've used Phabricator in other bugs, feel free to use it for this too.)
Hey, sorry I missed you on IRC. I saw you asked some questions about MFBT tests in #introduction. The tests are already written, in the existing patch attached to this bug (they are in the file mfbt/tests/TestFunctionRef.cpp). The patch also contains the change to add the tests to the build system (in the file mfbt/tests/moz.build). To run the tests locally, you would run <objdir>/mfbt/tests/TestFunctionRef (after building), as explained in comment 19. Finally, to get the tests to run in our automation as well, you need to modify testing/cppunittest.ini, as explained in comment 28. Let me know if that answers your question!
I followed the previous patch , and updated cppunittest.ini I formatted the files , plus tested it in build It works fine and can be reviewed now further
Attachment #9033059 - Attachment is obsolete: true
I was a bit late ,got in work I didn't knew of any way to revert to previous version So i thought the fastest way around to submit this patch was creating a new revision .Cause the work shouldn't stop

Hi Shivam, are you still working on this?

(In reply to Shubham Rawat from comment #38)

Hi Shivam, are you still working on this?

As we haven't heard from Shivam for a while, you're welcome to take over this bug if you're interested.

Before taking on this bug, please note what I've said in comment 2:

Should make a good mentored bug, maybe even a good first bug for someone who
has experience with C++ (i.e. if the code in comment 1 doesn't scare you,
this should be totally doable even if this is your first Mozilla bug).

That is, this is a "good first bug" for someone new to the Mozilla project, but not for someone new to C++ (it's fairly C++-intensive; understanding the code in comment 1 is a good litmus test).

(Shivam confirmed to me on IRC that he does not intend to continue working on this bug.)

(In reply to Botond Ballo [:botond] from comment #39)

I think this works well as my first bug in the Mozilla project. The LLVM implementation looks straight forward, and from a brief look I guess most of the work has been completed by previous assignee(s).

I think the latest patch was stuck on a test failure, I'll investigate it once I have the basic setup working. Does that sound good?

Ok, sounds good! Thanks Shubham.

Here are some instructions for checking out and building the Firefox source code: https://developer.mozilla.org/en-US/Simple_Firefox_build

Let me know once you've done that and we can discuss further steps.

Hey, is this up for grabs?

We haven't heard from Shubham in two weeks, so yes, I'd say it's up for grabs.

If you're interested in taking it on, please start by taking a look at comment 1. If you're comfortable with the sort of C++ code in comment 1, this could be a good bug for you; in that case, please see comment 42 for how to get started. (If you're not comfortable with the code in comment 1, please choose a different mentored bug.)

Actually I was planning to work on it, couldn't get the time these past couple of weeks. However if this is urgent, I think vskaulagi can take this up.

@vskaulagi Could you please let me know if you're working on this (in a week or so)? That's around when I was going to work on this bug.

Shubham I'll try to complete this one by the end of this week. If it's not done by then you can take it up, since you're anyway planning to work on it next week only.
Thanks.

Hi Vaishnavi, wanted to confirm if you're taking this up?

Hi Shubham, sure you can go ahead with it, I'm working on another bug.

Hey @botond, I've finally gotten around to getting everything setup. Need to get familiar with the phabricator/mercurial workflow before I can get started on this, taking a look at https://moz-conduit.readthedocs.io/en/latest/phabricator-user.html. Does that sound fine?

Yup, sounds good!

Hi,
I would like to volunteer. Thanks

Flags: needinfo?(botond)

Hi, thanks for your interest!

Please see what I wrote previously for how to get started:

(In reply to Botond Ballo [:botond] from comment #44)

If you're interested in taking it on, please start by taking a look at comment 1. If you're comfortable with the sort of C++ code in comment 1, this could be a good bug for you; in that case, please see comment 42 for how to get started. (If you're not comfortable with the code in comment 1, please choose a different mentored bug.)

Flags: needinfo?(botond)

Hi, is this bug still available?

Flags: needinfo?(botond)

Hi Sanchit -- yes, this is still something we'd like to have, and the bug is available to be worked on if you're interested!

Please see comment 44 for how to get started.

Flags: needinfo?(botond)
Assignee: nobody → fronkc1
Status: NEW → ASSIGNED

This had been quiet for a month, so I took a stab at it based on latest patch. The tests are passing for me and I believe I addressed all of the review comments from the original patch but please let me know if I missed anything.

My review comments started sprawling a little, so I've imported the patch here locally and just directly made the changes. I'm done making those changes and am currently reviewing the diff to ensure I understand all the changes and that they make sense.

The possible last holdup is that the using Type = decltype(test(0, mozilla::DeclVal<Func&>())); in the current patch somehow in my iteration of the patch is causing compile errors for FunctionRef(nullptr), such that instead of specializing EnableMatchingFunction for std::nullptr_t I need to specialize GetCallableTag instead. I'm not sure just what's up with that yet. Should be something I can figure out today (Wednesday), tho, I hope, then I can (I guess) commandeer the original rev and have everyone previously involved review it themselves.

Attachment #9126298 - Attachment description: Bug 1490781 - Add FunctionRef a non-owning ref to a Callable r=botond → Bug 1490781 - Add FunctionRef, a non-owning reference to a callable value (function pointer, lambda, etc.). r=botond
Attachment #9126298 - Attachment description: Bug 1490781 - Add FunctionRef, a non-owning reference to a callable value (function pointer, lambda, etc.). r=botond → Bug 1490781 - Add FunctionRef, a non-owning reference to a callable value (function pointer, lambda, etc.). r=botond!

(In reply to Jeff Walden [:Waldo] from comment #57)

The possible last holdup is that the using Type = decltype(test(0, mozilla::DeclVal<Func&>())); in the current patch somehow in my iteration of the patch is causing compile errors for FunctionRef(nullptr), such that instead of specializing EnableMatchingFunction for std::nullptr_t I need to specialize GetCallableTag instead. I'm not sure just what's up with that yet.

The reason for this was that in the previous patch we had

  FunctionRef() = default;
  MOZ_IMPLICIT FunctionRef(std::nullptr_t) ... { ... }

but my changes had instead made it

  MOZ_IMPLICIT FunctionRef(std::nullptr_t) ... { ... }
  FunctionRef() : FunctionRef(nullptr) {}

and apparently, our tests in the latter case will try to do overload matching against nullptr, but in the former case -- I'm not sure why -- they do not. So I think it's relatively likely the prior patch, had you ever actually passed nullptr to the constructor, would have failed to compile. (Don't ask me why mozilla::FunctionRef<int(int)> f2 = nullptr; doesn't trigger the same overload matching in both cases. Maybe implicit conversions have different overload behavior? Too lazy to check.)

Attachment #9033699 - Attachment is obsolete: true
Attachment #9126298 - Attachment description: Bug 1490781 - Add FunctionRef, a non-owning reference to a callable value (function pointer, lambda, etc.). r=botond! → Bug 1490781 - Add FunctionRef, a non-owning reference to a callable value (function pointer, lambda, etc.). r=botond!, r=ChrisFronk

It looks like I was added as reviewer on latest patch but I don't have permissions to accept the revision I'm getting access denied.

Flags: needinfo?(nfroyd)

(In reply to Chris Fronk from comment #59)

It looks like I was added as reviewer on latest patch but I don't have permissions to accept the revision I'm getting access denied.

I do not understand the inner workings of phab, but as far as I do understand them (and accept what other people tell me), you should be able to review this. Just to make sure...are you logged in, etc.? If the basics are in place, we should file a bug about this.

Flags: needinfo?(nfroyd)
Attachment #9126298 - Attachment description: Bug 1490781 - Add FunctionRef, a non-owning reference to a callable value (function pointer, lambda, etc.). r=botond!, r=ChrisFronk → Bug 1490781 - Add FunctionRef, a non-owning reference to a callable value (function pointer, lambda, etc.). r=botond!,ChrisFronk!

A double checked I was logged in and logged in account matched with where I was listed under reviewer. A lot of google searching and I believe issue is that because I created the revision is why phabricator won't allow me to approve it, but the info I could find is sparse. Searching in bugzilla for similar bugs I couldn't find anything similar. If you think I should file a bug should it be under infrastructure & operations?

This is what I get

    You do not have permission to edit this object.
    Users with the "Can Edit" capability:
    Members of the project "Restricted Project" can take this action.
    The owner of a revision can always view and edit it

Weird. I've asked about this in #conduit, we'll see what they say.

(In reply to Chris Fronk from comment #61)

If you think I should file a bug should it be under infrastructure & operations?

Here is the component for filing a bug related to Phabricator.

In the meantime, if you think the patch is in a good shape to land, you can indicate that in a comment in lieu of officially accepting it.

Blocks: 1624495

Thanks for link searching there I was able to find a similar issue and looks like I just need to be added to the editbugs group. I filed a bug to request that https://bugzilla.mozilla.org/show_bug.cgi?id=1624499.

I'm good with the patch Jeff added, and appreciate the updates/feedback he gave.

I've filed https://bugzilla.mozilla.org/show_bug.cgi?id=1624495 for the move-only arguments enhancement.

Thanks for taking a look! LEEROY JEEENNNKIIIINNNSSSS!

Pushed by jwalden@mit.edu: https://hg.mozilla.org/integration/autoland/rev/fe95f6067813 Add FunctionRef, a non-owning reference to a callable value (function pointer, lambda, etc.). r=botond
Status: ASSIGNED → RESOLVED
Closed: 5 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla76
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: