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

Create a LocalVector with capacity. #37370

Closed
wants to merge 1 commit into from

Conversation

reduz
Copy link
Member

@reduz reduz commented Mar 27, 2020

Will eventually use for some things I have planned, in the meantime feel free to review.

Currently Vector<> is used for most things because it has copy on write and you can pass it safely around. For some uses where you want to keep the array local, having a non-cow version with capacity is more useful because of performance and improved memory utilization.

Fixes #24731

} else {
capacity <<= 1;
}
data = (T *)memrealloc(data, capacity);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we care about non-trivial move/copy constructors?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think the compiler macro below handles it

Copy link
Contributor

@Zylann Zylann Mar 28, 2020

Choose a reason for hiding this comment

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

memralloc doesn't. Talking about move/copy here (for all elements being moved due to the realloc), not construct ;) or maybe it's ok and even STL doesn't do it either, I don't know

Copy link
Member Author

Choose a reason for hiding this comment

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

STL does not do either, it's common in this case.

T *data = nullptr;

public:
_FORCE_INLINE_ void push_back(T p_elem) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we have a pop_back()?

sort_custom<_DefaultComparator<T>>();
}

void ordered_insert(T p_val) {
Copy link
Contributor

Choose a reason for hiding this comment

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

If the goal of this function is to do ordered insert in a sorted array, shouldn't it better use a binary search to find the insertion point? It would assume the array is sorted though, so I wonder why such method would be part of this class

Copy link
Member Author

Choose a reason for hiding this comment

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

Depends, for large arrays binary search is faster, but for smaller ones, iterating is faster

data[count].~T();
}
}

Copy link
Member

Choose a reason for hiding this comment

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

An unordered O(1) remove is also very useful too, i.e.

remove_unordered(U p_index)
{
// swap p_index element with last
// remove last element so no copying needed
}

Copy link

Choose a reason for hiding this comment

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

might be nicer to have this be default remove behavior. It seems like more often unordered data is suitable for vectors.

I think an explicit OrderedLocalVector class would be useful, in addition to having a shared interface for Vector and LocalVector so then you can choose behavior and optimization with a consistent API for the data structures.

Copy link
Contributor

Choose a reason for hiding this comment

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

I disagree that this should be default. Ordered remove is de-facto standard, making unordered default would create confusion. Besides, I even do such unordered removal explicitely all the time because it often matters what this actually does (in a loop where you may remove elements, for example).

}
}

_FORCE_INLINE_ U size() const { return count; }
Copy link
Member

Choose a reason for hiding this comment

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

Could possibly do with a shrink_to_fit() or compact() call to free memory no longer required? As is, it looks like the only way to free memory is to delete the vector.

}

void remove(U p_index) {
ERR_FAIL_UNSIGNED_INDEX(p_index, count);
Copy link
Member

Choose a reason for hiding this comment

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

In the case of POD types, these 'mass movements' may be quicker with memmove / memcpy. I'm not sure the compiler will be able to substitute these automatically (not tested though).

}
count = p_size;
}
}
Copy link
Member

@lawnjelly lawnjelly Apr 4, 2020

Choose a reason for hiding this comment

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

It could be worth adding an additional mechanism for access without bounds checks, for performance critical code (e.g. renderer). In some situations the bounds check can result in considerable slowdown. (That's assuming CRASH_BAD_UNSIGNED_INDEX is being called in release too, if not, then this is less pressing)

Copy link
Contributor

@Zylann Zylann Apr 4, 2020

Choose a reason for hiding this comment

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

I agree it's not a big deal if bound checks are removed only on release.

@akien-mga
Copy link
Member

Force pushed a rebased commit to fix CI build.

@aaronfranke
Copy link
Member

Is it a good idea to name this type based on its intended usage rather than its specific functionality? Might be better as "FixedVector" or something since it has a fixed capacity.

@Zylann
Copy link
Contributor

Zylann commented Apr 24, 2020

@aaronfranke it doesn't have fixed capacity. U is the type used to represent sizes.

@reduz
Copy link
Member Author

reduz commented May 1, 2020

superseded by #38386

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Vector<T> does not yield performance results that capacity usually would
7 participants