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
Try out TileManager visitor #1403
base: master
Are you sure you want to change the base?
Conversation
Technically |
Perhaps it should be findFirst and visitAll. I don't think findIndex is too useful we don't normally use index's. |
As for additional parameters you could just have variadic template args after the visitor which you can just forward, TileManager::visitFirst<BuildingElement>(pos, [](BuildingElement& elBuilding, int32_t baseZ) {
if (elBuilding.baseZ() != baseZ())
{
return false;
}
elBuilding.setConstructed(isConstructed);
elBuilding.setUnk5u(newUnk5u);
elBuilding.setAge(newAge);
Ui::ViewportManager::invalidate(pos, elBuilding.baseZ() * 4, elBuilding.clearZ() * 4, ZoomLevel::quarter);
return true;
}, baseZ); Now it would be a pure function. |
@duncanspumpkin how about just We will also want to have common find methods anyway, like in OpenRCT2, we have |
I find the openrct2 ones quite inflexible leading to lots of similarly named functions. I was thinking perhaps we could have some common search functions like an atHeight noGhosts which you could combine together. So it would end up |
Maybe we could have some sort of method chain... auto el = tile.find<BuildingElement>()
.withZ(25)
.noGhosts()
.where([](auto& b) { return customPredicate; }; |
I'm not sure how that would work in c++. |
Only way I can think of doing it, is to have it set optional fields on a struct which is used for the search. But this is likely to not get optimised by the compiler. |
This is called a fluent interface or fluent api. You just have a set of methods perform a single operation and then return the (mutated) object for the next caller. Eg https://levelup.gitconnected.com/method-chaining-with-fluent-interface-pattern-d01e75d4bb3d I have experience with this in C# with LINQ, which is a fluent api defined on IEnumerable (which is basically just a list exposed only via iterators). Sadly there is no getting around iterating the entire list every time you make a fluent 'chain' call, and you have to implement it smartly for it to not constantly allocate for the new 'list'. I think if you implement the api on the iterator instead of the container, then you won't need any allocations to implement it. As for the actual implementation in C++, you'd use ranges as they are more or less the C++ 'equivalent' of IEnumerable from C#. |
Yeah i had a look at cinq which is a c++ linq wrapper but it has to allocate to handle things. Ranges is all c++20 so not sure we could use it on all platforms. But perhaps i should look into how it handles it. |
Oh cool, hadn't heard of cinq before but that looks like exactly what you want. But yeah I think LINQ in C# also allocates, its definitely not efficient, every time I use it in production code I have to consider the performance implications of evaluating the full list. |
Just trying to simiplify the code we use for accessing tile elements what about the below:
Advantages:
Tile
.visitAll
,visitFirst
Disadvantages:
visitFirst
needs the return true/false whilstvisitAll
does not.Visitor
and aUnaryPredicate
search function (this might also solve the no sharing betweenvisitFirst
visitAll