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

Feature/pool/pooled trails #5121

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

EatThePath
Copy link
Contributor

This branch is a test case for a new generational index based data structure that aims to replace our linked lists. The expected outcomes include safer references between objects, fewer stale pointer or index related issues, better iteration performance especially over long play sessions and easy switching from fixed length to variable length data structures.

This branch is not finished, but it is in a state where others may be able to usefully comment on the idioms in it and point out any missteps or missed opportunities.

The code in pool.h is definitely not done, nor very presentable. Trails.cpp contains the most examples of lower level pointer junk needing to be rewritten, and the rest show what changes have been required in routine external code having to touch trails.

I'm open to both hearing about ways this switch can be made more seamless, and also "while we're at it" ideas on ways we can improve the codebase's long term health by deviating a bit more.

@EatThePath
Copy link
Contributor Author

one thing to add: I set up a test mod to as much as I can stress trail creation, iteration and destruction for bench marking purposes. The branch and the baseline are so close together in performance I would call it measurement error, save for the fact that in nearly every case the branch is ever so slightly faster than the baseline. The baseline code isn't really a hot spot even in my most taxing test case so it's not too surprising that it's not a significant difference, but the trend is encouraging for the possibility of performance gains when applied more broadly.

@wookieejedi wookieejedi added cleanup A modification or rewrite of code to make it more understandable or easier to maintain. graphics A feature or issue related to graphics (2d and 3d) labels Jan 17, 2023
Copy link
Member

@BMagnu BMagnu left a comment

Choose a reason for hiding this comment

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

Okay, I've had a look at this.
Errm, I may have been a bit strict, but since this is a very cool thing to have for the SCP in wide usage as a generic container, I'd want it to be as polished as possible.

code/globalincs/pool.h Outdated Show resolved Hide resolved
code/globalincs/pool.h Outdated Show resolved Hide resolved
code/globalincs/pool.h Outdated Show resolved Hide resolved
code/globalincs/pool.h Outdated Show resolved Hide resolved
* Internal function to expand the storage list with a new object
* for use when there are no empty slots and the storage is not capped
*/
pool_index add_new(T &in){
Copy link
Member

Choose a reason for hiding this comment

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

both add_new and use_free really should use perfect forwarding to allow moving objects into a pool or creating them in place.

Comment on lines 299 to 295
iter(SCP_Pool<T> *vec_ptr, storage_p storage_ptr){
storage = storage_ptr;
vec = vec_ptr;
};
Copy link
Member

Choose a reason for hiding this comment

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

This construtor probably should not exist, or at the very least, just be an alias to iter(..., ..., 0), as it allows to create an iterator that points to an invalid element if element 0 is empty

SCP_Pool<T>::iter end(){
return iter(this,&storage,(int) storage.size());
}
};
Copy link
Member

Choose a reason for hiding this comment

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

Now that we've had so much fun with this iterator, how about we do it again.
On a serious note, having a const_iterator that does basically the same except returning const references is absolutely needed here.
Both are cbegin and cend useful overloads to enable optimizations, having a SCP_Pool<T>::const_iterator begin() const; overload is cruical to allow foreaching and iterating the pool even when we just have a const reference to it, which tends to be often.

code/globalincs/pool.h Outdated Show resolved Hide resolved
code/globalincs/pool.h Outdated Show resolved Hide resolved
//#include <vector>

using tl::optional;
struct pool_index{
Copy link
Member

Choose a reason for hiding this comment

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

Can we call it SCP_pool_index, just to keep the naming consistent with the pool itself?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

for myself ergonomics overcomes consistency in this case. pool_index is already more than I'd like to be typing for this, honestly. Since it's going to be used all over the damn place in the end I'm more than willing to bend to consensus on this one, if one can be established.

@EatThePath EatThePath force-pushed the feature/pool/pooled-trails branch from e0b82cb to 2d126f0 Compare January 22, 2023 04:33
@EatThePath EatThePath force-pushed the feature/pool/pooled-trails branch from 2d126f0 to a0a19b6 Compare January 23, 2023 00:58
@EatThePath EatThePath force-pushed the feature/pool/pooled-trails branch from a0a19b6 to 1eb8dfb Compare January 23, 2023 04:52
Copy link
Member

@BMagnu BMagnu left a comment

Choose a reason for hiding this comment

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

Yup, iterator looks better now, apart from the comments that are yet unresolved

*************************************************************************/
vector<gEntry<T>> storage;
vector<size_t> known_empty;

Copy link
Member

Choose a reason for hiding this comment

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

Probably needs to be !std::is_reference<T>::value, since the () operator is C++14

Comment on lines 237 to 285
tl::optional<pool_index> get_new(){
T n = T();
return store(n);
};

tl::optional<pool_index> get_new(T&& args){
T n = T(std::forward<T>(args));
return store(n);
};
Copy link
Member

Choose a reason for hiding this comment

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

Close, but now you still expect someone to construct the element for you (and forwarding that), instead of forwarding the args themselves to the constructor.
Effectively, I'd expect something like:

template<typename... args_t>
tl::optional<pool_index> get_new(args_t&&... args){
	return store(T(std::forward<args_t>(args)...));
};

code/globalincs/pool.h Outdated Show resolved Hide resolved
@Goober5000 Goober5000 added the Waiting for Stable Marks a pull request that is to be merged after the next stable release, due to a release cycle label Jan 26, 2023
@EatThePath EatThePath force-pushed the feature/pool/pooled-trails branch from 1eb8dfb to 0ca45c4 Compare January 27, 2023 23:11
@BMagnu BMagnu removed the Waiting for Stable Marks a pull request that is to be merged after the next stable release, due to a release cycle label Feb 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cleanup A modification or rewrite of code to make it more understandable or easier to maintain. graphics A feature or issue related to graphics (2d and 3d)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants