-
Notifications
You must be signed in to change notification settings - Fork 12k
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
base: main
Are you sure you want to change the base?
Conversation
✅ With the latest revision this PR passed the C/C++ code formatter. |
To-do list:
|
a4127b3
to
22903da
Compare
22903da
to
47615ff
Compare
91e3d83
to
8d29e36
Compare
8d29e36
to
440c327
Compare
} | ||
template <_ContainerCompatibleRange<_Tp> _Range> | ||
constexpr _LIBCPP_HIDE_FROM_ABI inplace_vector(from_range_t, _Range&& __rg) : inplace_vector() { | ||
append_range<true>(__rg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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?
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); |
There was a problem hiding this comment.
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))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} 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.
_LIBCPP_BEGIN_NAMESPACE_STD | ||
|
||
#if _LIBCPP_STD_VER >= 26 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 { |
There was a problem hiding this comment.
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?
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(); } |
There was a problem hiding this comment.
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]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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_; |
There was a problem hiding this comment.
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.
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 onT
andN
(at least large enough to hold up toN
). Or ifN == 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