tint/utils/vector: Allow use of incomplete types

Attempting to make a Vector of an incomplete pointer type would trigger an error as the `CanReinterpretSlice` trail magic is wanting to know the base types, which isn't known yet.

Split `CanReinterpretSlice` into class specializations, where the common case of no-cast doesn't look at the base types.

Change-Id: Id016b027b131f7988ccf3cae93622dacb7802a1d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/98140
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2022-08-17 15:42:15 +00:00 committed by Dawn LUCI CQ
parent 6e716c77ac
commit 81f0686523
1 changed files with 45 additions and 10 deletions

View File

@ -104,22 +104,42 @@ struct Slice {
auto rend() const { return std::reverse_iterator<const T*>(begin()); } auto rend() const { return std::reverse_iterator<const T*>(begin()); }
}; };
namespace detail {
/// Private implementation of tint::utils::CanReinterpretSlice.
/// Specialized for the case of TO equal to FROM, which is the common case, and avoids inspection of
/// the base classes, which can be troublesome if the slice is of an incomplete type.
template <typename TO, typename FROM>
struct CanReinterpretSlice {
/// True if a slice of FROM can be reinterpreted as a slice of TO
static constexpr bool value =
// Both TO and FROM are pointers
(std::is_pointer_v<TO> && std::is_pointer_v<FROM>)&& //
// const can only be applied, not removed
(std::is_const_v<std::remove_pointer_t<TO>> ||
!std::is_const_v<std::remove_pointer_t<FROM>>)&& //
// TO and FROM are both Castable
IsCastable<std::remove_pointer_t<FROM>, std::remove_pointer_t<TO>> && //
// FROM is of, or derives from TO
traits::IsTypeOrDerived<std::remove_pointer_t<FROM>, std::remove_pointer_t<TO>>;
};
/// Specialization of 'CanReinterpretSlice' for when TO and FROM are equal types.
template <typename T>
struct CanReinterpretSlice<T, T> {
/// Always `true` as TO and FROM are the same type.
static constexpr bool value = true;
};
} // namespace detail
/// Evaluates whether a `vector<FROM>` and be reinterpreted as a `vector<TO>`. /// Evaluates whether a `vector<FROM>` and be reinterpreted as a `vector<TO>`.
/// Vectors can be reinterpreted if both `FROM` and `TO` are pointers to a type that derives from /// Vectors can be reinterpreted if both `FROM` and `TO` are pointers to a type that derives from
/// CastableBase, and the pointee type of `TO` is of the same type as, or is an ancestor of the /// CastableBase, and the pointee type of `TO` is of the same type as, or is an ancestor of the
/// pointee type of `FROM`. Vectors of non-`const` Castable pointers can be converted to a vector of /// pointee type of `FROM`. Vectors of non-`const` Castable pointers can be converted to a vector of
/// `const` Castable pointers. /// `const` Castable pointers.
template <typename TO, typename FROM> template <typename TO, typename FROM>
static constexpr bool CanReinterpretSlice = static constexpr bool CanReinterpretSlice = detail::CanReinterpretSlice<TO, FROM>::value;
// TO and FROM are both pointer types
std::is_pointer_v<TO> && std::is_pointer_v<FROM> && //
// const can only be applied, not removed
(std::is_const_v<std::remove_pointer_t<TO>> ||
!std::is_const_v<std::remove_pointer_t<FROM>>)&& //
// TO and FROM are both Castable
IsCastable<std::remove_pointer_t<FROM>, std::remove_pointer_t<TO>> &&
// FROM is of, or derives from TO
traits::IsTypeOrDerived<std::remove_pointer_t<FROM>, std::remove_pointer_t<TO>>;
/// Reinterprets `const Slice<FROM>*` as `const Slice<TO>*` /// Reinterprets `const Slice<FROM>*` as `const Slice<TO>*`
/// @param slice a pointer to the slice to reinterpret /// @param slice a pointer to the slice to reinterpret
@ -440,6 +460,21 @@ class Vector {
/// @returns the end for a reverse iterator /// @returns the end for a reverse iterator
auto rend() const { return impl_.slice.rend(); } auto rend() const { return impl_.slice.rend(); }
/// Equality operator
/// @param other the other vector
/// @returns true if this vector is the same length as `other`, and all elements are equal.
bool operator==(const Vector& other) const {
const size_t len = Length();
if (len == other.Length()) {
for (size_t i = 0; i < len; i++) {
if ((*this)[i] != other[i]) {
return false;
}
}
}
return true;
}
private: private:
/// Friend class (differing specializations of this class) /// Friend class (differing specializations of this class)
template <typename, size_t> template <typename, size_t>