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

[libc++] Implement std::inplace_vector<T, N> #105981

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

MitalAshok
Copy link
Contributor

P0843R14 https://wg21.link/P0843R14: std::inplace_vector<T, N>

The ABI of this class is an array of T[N] followed by a __small_size_type member to hold the size, which is some unsigned integral type depending on T and N (at least large enough to hold up to N). Or if N == 0, an empty class as mandated by the standard.

This is not the fastest implementation. It aims to be correct and able to be optimised in the future in an ABI compatible way.

Closes #105433

Copy link

github-actions bot commented Aug 25, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@MitalAshok
Copy link
Contributor Author

MitalAshok commented Aug 25, 2024

To-do list:

  • Finish up tests
    • I copied over the vector tests and removed asan/allocator tests. Finish rewriting them in terms of inplace_vector.
    • Add new tests for inplace_vector specific members
  • Verify the layout is good (i.e., the type of __sz_, the order of members)

}
template <_ContainerCompatibleRange<_Tp> _Range>
constexpr _LIBCPP_HIDE_FROM_ABI inplace_vector(from_range_t, _Range&& __rg) : inplace_vector() {
append_range<true>(__rg);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
append_range<true>(__rg);
append_range(std::forward<_Range>(__rg));

This line does not compile on my machine. I guess this was supposed to forward to the append_range member function?

Comment on lines +227 to +231
if constexpr (_MaximumPadding >= sizeof(size_t)) {
// Unconditionally use size_t in this case. Using a smaller size
// will not change the size of the inplace_vector because it will
// only introduce more padding bits
return static_cast<size_t>(0);
Copy link
Contributor

Choose a reason for hiding this comment

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

Not using size_t would allow others (e.g. expected) to use the padding bytes though, so we should still use a smaller type.

// will not change the size of the inplace_vector because it will
// only introduce more padding bits
return static_cast<size_t>(0);
} else if constexpr (_Capacity <= static_cast<unsigned char>(-1) && (sizeof(unsigned char) < sizeof(size_t))) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
} else if constexpr (_Capacity <= static_cast<unsigned char>(-1) && (sizeof(unsigned char) < sizeof(size_t))) {
} else if constexpr (_Capacity <= numeric_limits<unsigned char>::max() && (sizeof(unsigned char) < sizeof(size_t))) {

Why do you check for sizeof(T) < sizeof(size_t)? It's not like we care in the end which type exactly is used.

Comment on lines +218 to +220
_LIBCPP_BEGIN_NAMESPACE_STD

#if _LIBCPP_STD_VER >= 26
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 26
#if _LIBCPP_STD_VER >= 26
_LIBCPP_BEGIN_NAMESPACE_STD

}

template <class _Tp, size_t _Capacity>
class _LIBCPP_TEMPLATE_VIS __inplace_vector_array {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
class _LIBCPP_TEMPLATE_VIS __inplace_vector_array {
class __inplace_vector_array {

It's and internal type, so it shouldn't need any annotations.

}

template <class _Tp, size_t _Capacity>
class _LIBCPP_TEMPLATE_VIS __inplace_vector_array {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why did you introduce a base class?

Comment on lines +596 to +612
constexpr _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return __make_iter(data()); }
constexpr _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __make_iter(data()); }
constexpr _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return __make_iter(data() + size()); }
constexpr _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __make_iter(data() + size()); }
constexpr _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
constexpr _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const noexcept {
return const_reverse_iterator(end());
}
constexpr _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
constexpr _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const noexcept {
return const_reverse_iterator(begin());
}

constexpr _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const noexcept { return begin(); }
constexpr _LIBCPP_HIDE_FROM_ABI const_iterator cend() const noexcept { return end(); }
constexpr _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const noexcept { return rbegin(); }
constexpr _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const noexcept { return rend(); }
Copy link
Contributor

Choose a reason for hiding this comment

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

These should probably all be [[nodiscard]].


template <class _First, class _Sent>
constexpr _LIBCPP_HIDE_FROM_ABI void __assign_with_size(_First&& __first, _Sent&& __sent, size_t __n) {
if (__n > capacity()) [[unlikely]]
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (__n > capacity()) [[unlikely]]
if (__n > capacity())

You call a [[noreturn]] function in this branch. The compiler already marks that us unlikely. No need to do it explicitly.

union {
_Tp __elems_[_Capacity];
};
__small_size_type __sz_;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should look into using #98498 here. It could be a really sweet optimization, but I don't know how much more code would be generated.

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.

P0843R14: inplace_vector
3 participants