Bug 143600

Summary: Use modern for-loops in Document
Product: WebKit Reporter: Joonghun Park <jh718.park>
Component: WebCore Misc.Assignee: Joonghun Park <jh718.park>
Status: RESOLVED FIXED    
Severity: Normal CC: commit-queue, darin, esprehn+autocc, gyuyoung.kim, kangil.han, ossy, rniwa
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch none

Description Joonghun Park 2015-04-10 01:37:12 PDT
Use modern for-loops in Document.
Comment 1 Joonghun Park 2015-04-10 02:09:15 PDT
Created attachment 250507 [details]
Patch
Comment 2 Csaba Osztrogonác 2015-04-10 04:45:10 PDT
Comment on attachment 250507 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=250507&action=review

> Source/WebCore/ChangeLog:3
> +        Use modern for-loops in Document

This title is misleading, I can't see any range-based 
loop, but replacing explicit types with autos.

> Source/WebCore/dom/Document.cpp:4441
> -    HashSet<Element*>::iterator end = m_privateBrowsingStateChangedElements.end();
> -    for (HashSet<Element*>::iterator it = m_privateBrowsingStateChangedElements.begin(); it != end; ++it)
> +    for (HashSet<Element*>::iterator it = m_privateBrowsingStateChangedElements.begin(), end = m_privateBrowsingStateChangedElements.end(); it != end; ++it)

why don't you use auto here similar to other places?
Comment 3 Joonghun Park 2015-04-10 06:37:01 PDT
(In reply to comment #2)
> Comment on attachment 250507 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=250507&action=review
> 
> > Source/WebCore/ChangeLog:3
> > +        Use modern for-loops in Document
> 
> This title is misleading, I can't see any range-based 
> loop, but replacing explicit types with autos.
> 
Oh, I mis-used the term 'modern for-loops'. I will change the title to 'Replace explicit types with auto in Document'. :)
> > Source/WebCore/dom/Document.cpp:4441
> > -    HashSet<Element*>::iterator end = m_privateBrowsingStateChangedElements.end();
> > -    for (HashSet<Element*>::iterator it = m_privateBrowsingStateChangedElements.begin(); it != end; ++it)
> > +    for (HashSet<Element*>::iterator it = m_privateBrowsingStateChangedElements.begin(), end = m_privateBrowsingStateChangedElements.end(); it != end; ++it)
> 
> why don't you use auto here similar to other places?
I will apply your comment :) Thank you~
Comment 4 Joonghun Park 2015-04-10 07:02:45 PDT
Created attachment 250517 [details]
Patch
Comment 5 Darin Adler 2015-04-10 09:24:42 PDT
Comment on attachment 250517 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=250517&action=review

All of these *could* use modern for loops. And should.

> Source/WebCore/dom/Document.cpp:3771
>      HashSet<NodeIterator*> nodeIteratorsList = m_nodeIterators;

Really strange to call this “list” when it’s a set, not a list.

> Source/WebCore/dom/Document.cpp:3772
> +    for (auto it = nodeIteratorsList.begin(), nodeIteratorsEnd = nodeIteratorsList.end(); it != nodeIteratorsEnd; ++it) {

This could be converted to a modern for loop:

    for (auto& iterator : nodeIteratorsList) {
        if (iterator->root() == node) {
            detachNodeIterator(iterator);

etc. Unless I am missing something.

> Source/WebCore/dom/Document.cpp:3816
> +    for (auto it = m_nodeIterators.begin(), nodeIteratorsEnd = m_nodeIterators.end(); it != nodeIteratorsEnd; ++it)

Same here.

> Source/WebCore/dom/Document.cpp:3820
> +        for (auto it = m_ranges.begin(), rangesEnd = m_ranges.end(); it != rangesEnd; ++it)

Same here.

> Source/WebCore/dom/Document.cpp:3871
> +        for (auto it = m_ranges.begin(), end = m_ranges.end(); it != end; ++it)

Same here.

> Source/WebCore/dom/Document.cpp:4375
> +    for (auto i = m_documentSuspensionCallbackElements.begin(), end = m_documentSuspensionCallbackElements.end(); i != end; ++i)

Same here.

> Source/WebCore/dom/Document.cpp:4394
> +    for (auto i = elements.begin(), end = elements.end(); i != end; ++i)

Same here.

> Source/WebCore/dom/Document.cpp:4441
> +    for (auto it = m_privateBrowsingStateChangedElements.begin(), end = m_privateBrowsingStateChangedElements.end(); it != end; ++it)

Same here.

> Source/WebCore/dom/Document.cpp:4471
> +    for (auto it = m_captionPreferencesChangedElements.begin(), end = m_captionPreferencesChangedElements.end(); it != end; ++it)

Same here.

> Source/WebCore/dom/Document.cpp:5451
> +    for (auto i = descendants.begin(); i != descendants.end(); ++i) {

Same here.
Comment 6 Joonghun Park 2015-04-10 18:30:02 PDT
(In reply to comment #5)
> Comment on attachment 250517 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=250517&action=review
> 
> All of these *could* use modern for loops. And should.
> 
You're right. I revised all of the things in the previous patches and more than that.
 
> > Source/WebCore/dom/Document.cpp:3771
> >      HashSet<NodeIterator*> nodeIteratorsList = m_nodeIterators;
> 
> Really strange to call this “list” when it’s a set, not a list.
> 
I changed list to set.
> > Source/WebCore/dom/Document.cpp:3772
> > +    for (auto it = nodeIteratorsList.begin(), nodeIteratorsEnd = nodeIteratorsList.end(); it != nodeIteratorsEnd; ++it) {
> 
> This could be converted to a modern for loop:
> 
>     for (auto& iterator : nodeIteratorsList) {
>         if (iterator->root() == node) {
>             detachNodeIterator(iterator);
> 
> etc. Unless I am missing something.
> 
Yepp, you're right. In addition I use auto* because its type is NodeInterator*.

> > Source/WebCore/dom/Document.cpp:3816
> > +    for (auto it = m_nodeIterators.begin(), nodeIteratorsEnd = m_nodeIterators.end(); it != nodeIteratorsEnd; ++it)
> 
> Same here.
> 
> > Source/WebCore/dom/Document.cpp:3820
> > +        for (auto it = m_ranges.begin(), rangesEnd = m_ranges.end(); it != rangesEnd; ++it)
> 
> Same here.
> 
> > Source/WebCore/dom/Document.cpp:3871
> > +        for (auto it = m_ranges.begin(), end = m_ranges.end(); it != end; ++it)
> 
> Same here.
> 
> > Source/WebCore/dom/Document.cpp:4375
> > +    for (auto i = m_documentSuspensionCallbackElements.begin(), end = m_documentSuspensionCallbackElements.end(); i != end; ++i)
> 
> Same here.
> 
> > Source/WebCore/dom/Document.cpp:4394
> > +    for (auto i = elements.begin(), end = elements.end(); i != end; ++i)
> 
> Same here.
> 
> > Source/WebCore/dom/Document.cpp:4441
> > +    for (auto it = m_privateBrowsingStateChangedElements.begin(), end = m_privateBrowsingStateChangedElements.end(); it != end; ++it)
> 
> Same here.
> 
> > Source/WebCore/dom/Document.cpp:4471
> > +    for (auto it = m_captionPreferencesChangedElements.begin(), end = m_captionPreferencesChangedElements.end(); it != end; ++it)
> 
> Same here.
> 
> > Source/WebCore/dom/Document.cpp:5451
> > +    for (auto i = descendants.begin(); i != descendants.end(); ++i) {
> 
> Same here.

Thank you for your kind review and teaching, Darin :)
Comment 7 Joonghun Park 2015-04-10 18:31:23 PDT
Created attachment 250549 [details]
Patch
Comment 8 Joonghun Park 2015-04-10 18:46:15 PDT
Created attachment 250553 [details]
Patch
Comment 9 Joonghun Park 2015-04-10 18:54:59 PDT
Created attachment 250555 [details]
Patch
Comment 10 Darin Adler 2015-04-10 19:04:25 PDT
Comment on attachment 250555 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=250555&action=review

review- because of the mistake below where we do return instead of break; other comments are all just ways to slightly improve

> Source/WebCore/dom/Document.cpp:2819
> +            return;

This needs to be "break", not "return"!

Also, I suggest putting it at the end of the loop body rather than the start; either is OK but I think it makes better logical sense at the end.

Or we could change it to only check after setting href or target like this:

    ... {
        href = &value;
        if (target)
            break;
    }

    ... {
        target = &value
        if (href)
            break;
    }

> Source/WebCore/dom/Document.cpp:3773
> +    HashSet<NodeIterator*> nodeIteratorsSet = m_nodeIterators;

Could use auto here; not sure it would be better. Could also change this to use copyToVector instead of copying into another set. I believe that would be more efficient than copying the set, although the code would read as less elegant.

> Source/WebCore/dom/Document.cpp:3784
>      if (!m_ranges.isEmpty()) {

This if statement should be removed. The loop in the body will already efficiently do nothing if m_ranges is empty.

> Source/WebCore/dom/Document.cpp:3792
>      if (!m_ranges.isEmpty()) {

This if statement should be removed. The loop in the body will already efficiently do nothing if m_ranges is empty.

> Source/WebCore/dom/Document.cpp:3821
>      if (!m_ranges.isEmpty()) {

This if statement should be removed. The loop in the body will already efficiently do nothing if m_ranges is empty.

> Source/WebCore/dom/Document.cpp:3872
>      if (!m_ranges.isEmpty()) {

This if statement should be removed. The loop in the body will already efficiently do nothing if m_ranges is empty.
Comment 11 Joonghun Park 2015-04-10 20:22:45 PDT
(In reply to comment #10)
> Comment on attachment 250555 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=250555&action=review
> 
> review- because of the mistake below where we do return instead of break;
> other comments are all just ways to slightly improve
> 
> > Source/WebCore/dom/Document.cpp:2819
> > +            return;
> 
> This needs to be "break", not "return"!
> 
> Also, I suggest putting it at the end of the loop body rather than the
> start; either is OK but I think it makes better logical sense at the end.
> 
> Or we could change it to only check after setting href or target like this:
> 
>     ... {
>         href = &value;
>         if (target)
>             break;
>     }
> 
>     ... {
>         target = &value
>         if (href)
>             break;
>     }
> 
Ouch, I corrected the mistake I made. And your suggestion is really cool :)
I applied your idea.
> > Source/WebCore/dom/Document.cpp:3773
> > +    HashSet<NodeIterator*> nodeIteratorsSet = m_nodeIterators;
> 
> Could use auto here; not sure it would be better. Could also change this to
> use copyToVector instead of copying into another set. I believe that would
> be more efficient than copying the set, although the code would read as less
> elegant.
> 
I revised it to use vector instead of HashSet. I agree with you that it will be more efficient than to use HashSet.
> > Source/WebCore/dom/Document.cpp:3784
> >      if (!m_ranges.isEmpty()) {
> 
> This if statement should be removed. The loop in the body will already
> efficiently do nothing if m_ranges is empty.
> 
I applied this change.
> > Source/WebCore/dom/Document.cpp:3792
> >      if (!m_ranges.isEmpty()) {
> 
> This if statement should be removed. The loop in the body will already
> efficiently do nothing if m_ranges is empty.
> 
I applied this change.
> > Source/WebCore/dom/Document.cpp:3821
> >      if (!m_ranges.isEmpty()) {
> 
> This if statement should be removed. The loop in the body will already
> efficiently do nothing if m_ranges is empty.
> 
I applied this change.
> > Source/WebCore/dom/Document.cpp:3872
> >      if (!m_ranges.isEmpty()) {
> 
> This if statement should be removed. The loop in the body will already
> efficiently do nothing if m_ranges is empty.
I applied this change.
Comment 12 Joonghun Park 2015-04-10 20:27:55 PDT
Created attachment 250559 [details]
Patch
Comment 13 Joonghun Park 2015-04-10 21:24:44 PDT
Created attachment 250561 [details]
Patch
Comment 14 Darin Adler 2015-04-11 08:19:38 PDT
Comment on attachment 250561 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=250561&action=review

> Source/WebCore/dom/Document.cpp:5017
> +    for (auto it : m_textAutoSizedNodes) {

It would be more efficient to use auto& here; using auto means we copy both the key and value each time. It’s not great to name the loop variable “it” because it’s not an iterator.

> Source/WebCore/dom/Document.cpp:5018
> +        RefPtr<TextAutoSizingValue> value = it.value;

I wonder why we use a RefPtr here instead of a raw pointer. Seems like it might be unneeded reference count churn. The only reason to use a RefPtr would be if there is some risk that adjustNodeSizes might cause the value to be released, but if it does, then we have a bigger problem because if m_textAutoSizedNodes is modified while we are iterating it we have a problem.

> Source/WebCore/dom/Document.cpp:5029
>      unsigned count = nodesForRemoval.size();
>      for (unsigned i = 0; i < count; i++)

This should use a modern for loop.
Comment 15 Joonghun Park 2015-04-12 09:52:31 PDT
(In reply to comment #14)
> Comment on attachment 250561 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=250561&action=review
> 
> > Source/WebCore/dom/Document.cpp:5017
> > +    for (auto it : m_textAutoSizedNodes) {
> 
> It would be more efficient to use auto& here; using auto means we copy both
> the key and value each time. It’s not great to name the loop variable “it”
> because it’s not an iterator.
> 
I revised the name to keyValuePair instead of it.
> > Source/WebCore/dom/Document.cpp:5018
> > +        RefPtr<TextAutoSizingValue> value = it.value;
> 
> I wonder why we use a RefPtr here instead of a raw pointer. Seems like it
> might be unneeded reference count churn. The only reason to use a RefPtr
> would be if there is some risk that adjustNodeSizes might cause the value to
> be released, but if it does, then we have a bigger problem because if
> m_textAutoSizedNodes is modified while we are iterating it we have a problem.
> 
When I see in the adjustNodeSizes(), it seems that there is no such place in which releases the value itself, so I think RefPtr was used because it's simply the type of the HashMap's value. I changed it to raw pointer to avoid refCount churn as you pointed out.
> > Source/WebCore/dom/Document.cpp:5029
> >      unsigned count = nodesForRemoval.size();
> >      for (unsigned i = 0; i < count; i++)
> 
> This should use a modern for loop.
I changed this to use modern for loop.

Thank you for your review :)
Comment 16 Joonghun Park 2015-04-12 10:12:07 PDT
Created attachment 250610 [details]
Patch
Comment 17 Darin Adler 2015-04-12 12:44:26 PDT
Comment on attachment 250610 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=250610&action=review

> Source/WebCore/dom/Document.cpp:6100
> +    for (auto& keyValuePair : *targets) {

I noticed that this loop’s body only accesses the keys, so it could be:

    for (auto& key : targets->keys()) {
Comment 18 Joonghun Park 2015-04-12 17:36:24 PDT
(In reply to comment #17)
> Comment on attachment 250610 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=250610&action=review
> 
> > Source/WebCore/dom/Document.cpp:6100
> > +    for (auto& keyValuePair : *targets) {
> 
> I noticed that this loop’s body only accesses the keys, so it could be:
> 
>     for (auto& key : targets->keys()) {

The type of EventTargetSet is HashCountedSet<Node*>, so keys() is not a member of HashCountedSet.
If we have a function which return the member HashMap like 
hashMap() { return m_impl; } in HashCountedSet, 
then it would be possible to write as following,
    for (auto* key : targets->hashMap().keys())
but currently there is no function in HashCountedSet.
IMHO, I couldn't find a way to apply your comment. :)
Comment 19 Darin Adler 2015-04-13 08:40:20 PDT
(In reply to comment #18)
> (In reply to comment #17)
> > Comment on attachment 250610 [details]
> > Patch
> > 
> > View in context:
> > https://bugs.webkit.org/attachment.cgi?id=250610&action=review
> > 
> > > Source/WebCore/dom/Document.cpp:6100
> > > +    for (auto& keyValuePair : *targets) {
> > 
> > I noticed that this loop’s body only accesses the keys, so it could be:
> > 
> >     for (auto& key : targets->keys()) {
> 
> The type of EventTargetSet is HashCountedSet<Node*>, so keys() is not a
> member of HashCountedSet.
> If we have a function which return the member HashMap like 
> hashMap() { return m_impl; } in HashCountedSet, 
> then it would be possible to write as following,
>     for (auto* key : targets->hashMap().keys())
> but currently there is no function in HashCountedSet.
> IMHO, I couldn't find a way to apply your comment. :)

Makes sense. Some day we could add adapters to HashCountedSet like the ones we have for HashMap, but for now I understand that this can’t be done. We should not expose the HashMap, though.
Comment 20 WebKit Commit Bot 2015-04-13 22:49:24 PDT
Comment on attachment 250610 [details]
Patch

Clearing flags on attachment: 250610

Committed r182782: <http://trac.webkit.org/changeset/182782>
Comment 21 WebKit Commit Bot 2015-04-13 22:49:29 PDT
All reviewed patches have been landed.  Closing bug.