Skip to content
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

Refactor: Replace parts of boost::optional with std::optional (#6551,… #6593

Closed
wants to merge 13 commits into from

Conversation

mugr1x
Copy link
Contributor

@mugr1x mugr1x commented Apr 3, 2023

Issue

Since C++17 added support for 'containers', #6551 targets at replacing current code that uses boost::optional to use std::optional. This PR replaces some parts of the codebase with std::optional, indeed the ones I could convert without having to rewrite some parsers, see #6592 . I try complete these parser, but without that any further migrations to std::optional cause only myriads of compiler errors.

Please read our documentation on release and version management.
If your PR is still work in progress please attach the relevant label.

Tasklist

Requirements / Relations

#6551
#6592

@mugr1x mugr1x closed this Apr 3, 2023
@mugr1x
Copy link
Contributor Author

mugr1x commented Apr 3, 2023

Tests fail with segfault.

@mugr1x mugr1x reopened this Apr 3, 2023
@mugr1x
Copy link
Contributor Author

mugr1x commented Apr 3, 2023

Had something to do with DecreaseKey in query_heap.hpp.
EDIT: Sorry had submitted the wrong commit yesterday (i.e. the one that segfaults, I got around this by calling in DecreaseKey not boost::heap::increase as current master but boost::heap::decrease, hope this is right)
Regarding the errorrs in CI, are these formatting errors ? I ran scripts/format.sh as advised.

@mugr1x mugr1x force-pushed the boost_optional branch 2 times, most recently from 328eaaf to 97d3fcb Compare April 4, 2023 09:50
@mugr1x
Copy link
Contributor Author

mugr1x commented Apr 10, 2023

std::remove_if(non_core_edges.begin(), non_core_edges.end(), [&](const auto &edge) {
return is_shared_core[edge.source] && is_shared_core[edge.target];
});
auto new_end = std::remove_if(non_core_edges.begin(),
Copy link
Member

Choose a reason for hiding this comment

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

Hm, do I get it correctly that most of changes in this PR are format changes. Were they pushed by mistake?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Better now ?

@mugr1x mugr1x force-pushed the boost_optional branch 2 times, most recently from 1fc8d4c to f98d73c Compare April 14, 2023 18:37
@@ -289,7 +289,7 @@ class QueryHeap
return inserted_nodes[index].node == node;
}

boost::optional<HeapNode &> GetHeapNodeIfWasInserted(const NodeID node)
std::optional<HeapNode> GetHeapNodeIfWasInserted(NodeID node)
Copy link
Member

Choose a reason for hiding this comment

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

I.e. now on each call we will copy HeapNode, right? How do we know that it won’t impact performance? May be worth refactoring it to HeapNode* instead(I mean use just pointer instead of optional here)? From some perspective optional<T&> is just overcomplicated way to express simple pointer…

WDYT?

P.S. I didn’t have a time yet to look over the rest of PR, just something important what I noticed…

Copy link
Member

Choose a reason for hiding this comment

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

More than it: here you can see an example when we change contents of node in a heap and that by reference…

toHeapNode->data = {heapNode.node, true};

I.e. if we return it not by reference now most likely existing logic is broken.

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 did run my build and it did at least not segfault or got killed by kernel for too much RAM.
To cite from cppreference.com:
"There are no optional references; a program is ill-formed if it instantiates an optional with a reference type."
Search engine would suggest std::reference_wrapper for this task.

Copy link
Member

Choose a reason for hiding this comment

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

At the same time as I can see if we just change it to simple pointer instead of optional(I.e. won’t use neither boost::optional nor std::optional) the rest of code which uses this QueryHeap would “just work” without changes we had to make there…

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Regarding the other comment std::optional defines an operator->. However in some cases you probably would need to change a deref etc. I'm just testing solely using pointers for these parts. Does not work out of the box, but the idea should be doable.

Copy link
Member

Choose a reason for hiding this comment

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

boost::optional<T&> seems to be effectively the same as T*, isn’t 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.

Yes it is. Still forking the main branch I need replace some of the idioms. Do you prefer nullptr or some void coercion ?

Copy link
Member

Choose a reason for hiding this comment

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

What is void coercion? You mean if (ptr == nullptr) vs if (!ptr)? Personally I like first option as more explicit, but I don’t think it would be blocker to merge this PR :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually it's dreadfully simple, memory safety should be fine since it tests. I got too fed up with the nullptr version.
I think you need to approve CI again.

@mugr1x mugr1x force-pushed the boost_optional branch 2 times, most recently from 54ef1b3 to fb0400f Compare April 14, 2023 21:21
@@ -356,13 +356,13 @@ class QueryHeap
const auto index = node_index.peek_index(node);
auto &reference = inserted_nodes[index];
reference.weight = weight;
heap.increase(reference.handle, std::make_pair(weight, index));
heap.decrease(reference.handle, std::make_pair(weight, index));
Copy link
Member

Choose a reason for hiding this comment

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

This change is pretty fundamental to how the whole routing algorithm works. Can you explain exactly why this change is being made 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.

See my previous link posted above:
https://www.boost.org/doc/libs/1_76_0/doc/html/boost/heap/d_ary_heap.html#id-1_3_18_6_2_1_1_1_22_17-bb
My thoughts behind this are that there is logic in multiple files e.g. include/engine/routing_algorithms/routing_base_mld.hpp that checks for a certain "to_weight" to be smaller than the current "toHeapNode->weight" and then calls DecreaseKey which in turn calls heap.increase with "to_weight".
So the docs say: "The new value is expected to be less than the current one" for decrease not increase.
Also I guess it kinda fixed a segfault for me while testing. (I know for sure it was this one, however might only have emerged with now reverted changes since now not using std::optional instead just pointers)
Am I completely mistaken here ? I still get from A to B though using my setup e.g. with the Germany map.

Copy link
Member

@danpat danpat left a comment

Choose a reason for hiding this comment

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

Can you explain why the change from heap.increase() to heap.decrease() ? "The old version was wrong because XYZ?" is an acceptable answer, but this is a pretty fundamental change to a core part of the routing algorithm, I think it needs a clear rationale.

@mugr1x
Copy link
Contributor Author

mugr1x commented Apr 15, 2023

@SiarheiFedartsou @danpat
Can anyone please approve CI again ?

@danpat
Copy link
Member

danpat commented Apr 16, 2023

@mugr1x You didn't address my question about the changes in DecreaseKey in query_heap.hpp - why are those changes included? It's not obvious to me why changing to returning a pointer involves switching from .increase() to .decrease().

@mugr1x
Copy link
Contributor Author

mugr1x commented Apr 17, 2023

Well I linked the docs two times and explained my reasoning. I opened a separate issue #6603 for this but I would really advise you too look into this anyway soonish. As said I fixed a segfault at some point for me.
Also you are completely right it has nothing to do with just returning a pointer in GetHeapNodeIfWasInserted, however this is the same in master, because as Siarhei pointed out boost::optional<T&> is just a disguise for T*.
So the function always returned a pointer nothing is changed by me except the idiom.

@SiarheiFedartsou
Copy link
Member

Well I linked the docs two times and explained my reasoning. I opened a separate issue #6603 for this but I would really advise you too look into this anyway soonish.

Can we discuss that in separate PR? This change is serious enough to deserve separate PR... Also if you see that it doesn't work in certain cases it is always a good practice to add test for such case to not regress it in the future.

@mugr1x
Copy link
Contributor Author

mugr1x commented Apr 17, 2023

Well I linked the docs two times and explained my reasoning. I opened a separate issue #6603 for this but I would really advise you too look into this anyway soonish.

Can we discuss that in separate PR? This change is serious enough to deserve separate PR... Also if you see that it doesn't work in certain cases it is always a good practice to add test for such case to not regress it in the future.

Yes

@mugr1x
Copy link
Contributor Author

mugr1x commented Apr 17, 2023

I just noted that PR #6596 was merged, I had the same fix as that in this PR too. So I just resolved this one with master.

@AlTimofeyev
Copy link
Contributor

Hi @mugr1x , I took a glance at that error you mentioned and it looks like the file where block_counter is mentioned in your PR is redefined. Take a glance at your commits. File range_table.hpp has two definitions for that variable on lines 84 and 86. It must've happened when you resolved with master (my bad about that).

@mugr1x
Copy link
Contributor Author

mugr1x commented Apr 18, 2023

@danpat Are you happy with the current status ? If so can you close the review or similar.
@AlTimofeyev Yes, I first merged my own and your fix. You are right. I just did look at my local source not the the diff.
Thank you very much.

@SiarheiFedartsou SiarheiFedartsou requested a review from danpat April 18, 2023 21:17
@mugr1x
Copy link
Contributor Author

mugr1x commented Apr 19, 2023

CI shows exactly the same error about block_counter, which is weird since it is clearly only defined once now, also in diff.
Probably this has nothing to do with this PR, so merge anyway ?

@SiarheiFedartsou
Copy link
Member

@mugr1x may I ask you to create one more empty commit to trigger CI again? I suspect it is some bug in GitHub Actions.

BlockT block;
#ifndef BOOST_ASSERT_IS_VOID
unsigned block_counter = 0;
Copy link
Member

@danpat danpat Apr 19, 2023

Choose a reason for hiding this comment

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

These changes were merged to master in another PR #6596 - they should not also be showing up in this PR. I suspect some merges have been incorrectly applied or lost on the branch. This is probably also why CI is failing. I suspect if you tidy this up, CI should pass.

Copy link
Contributor

@AlTimofeyev AlTimofeyev Apr 20, 2023

Choose a reason for hiding this comment

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

The source code on master branch has block_counter = 0 on line 85, meanwhile in this commit it is placed on line 84. Could that be what's causing CI to fail?

Copy link
Member

Choose a reason for hiding this comment

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

@mugr1x may be try to squash all your commits into single one? Or open another PR? Tbh for me it is not clear why it is happening - looks more like some GH bug.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@AlTimofeyev Well yes. Idk that much about CI.
@SiarheiFedartsou I did so #6611. Should I close this one ?
I also tried to rewrite some parsers. Point here is that the ones that are easy to rewrite work fine with switching to std::optional but the /server core API (and /engine because it there are crosslinks) don't.
I think this would be considered a too breaking change (at least ~1k lines of code) of new parser-related code.
Do you think there is value in #6592 or should I close this too ?
Also off-topic, but did you receive my email regarding GSoC. I was asking for what you mentors would expect. (I submitted my second version a bit late, though in time. Hope that is not a problem.)

@mugr1x
Copy link
Contributor Author

mugr1x commented Apr 24, 2023

I just realized I had a lot of comments show as 'Pending', which means appearantly noone but me could seee those.
Anyway probably I should close this once the other PR is merged.

@mugr1x mugr1x closed this Apr 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants