tint/utils: More Vector polish
* Added a class template argument deduction guide (CTAD) to infer the `T` and `N` template arguments. This lets you write `Vector{1,2,3}` instead of `Vector<int, 3>{1,2,3}`. This is important as a mismatch between the number of constructor arguments and the `N` template argument can cause silent heap allocations, which we're trying to avoid. The `T` deduction uses the same smarts as the return-type deduction of `Switch()`, so: * `Vector{1, 2.0}` would construct a `Vector<double, 2>` * `Vector{i32, u32}` would construct a `Vector<const sem::Type*, 2>` * Removed the Vector(size_t) and Vector(size_t, const T&) constructors. This is a move away from the std::vector style API, but these are rarely more efficient than calling Reserve() and Push(), as you remove the redundant initialization. The main reason for doing this is to remove ambiguity between `Vector{1}` and `Vector(1)`. * Added support for covariance conversion (`Vector<Derived*, N>` -> `Vector<Base*, N>`). Only supports pointers to `Castable`, as this can only safely work with single-inheritance. * Added support for conversion of `Vector<T*, N>` -> `Vector<const T*, N>`. This will remove pointless vector copies from the sem package. Bug: tint:1613 Change-Id: I79b9f82d623f90afa14f8ba1613ee49cccceafeb Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/97020 Reviewed-by: Antonio Maiorano <amaiorano@google.com> Commit-Queue: Ben Clayton <bclayton@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
45db5df803
commit
4d1d143977
|
@ -44,10 +44,10 @@ TEST(HashTests, StdVector) {
|
|||
}
|
||||
|
||||
TEST(HashTests, TintVector) {
|
||||
EXPECT_EQ(Hash(Vector<int>({})), Hash(Vector<int>({})));
|
||||
EXPECT_EQ(Hash(Vector<int>({1, 2, 3})), Hash(Vector<int>({1, 2, 3})));
|
||||
EXPECT_NE(Hash(Vector<int>({1, 2, 3})), Hash(Vector<int>({1, 2, 4})));
|
||||
EXPECT_NE(Hash(Vector<int>({1, 2, 3})), Hash(Vector<int>({1, 2, 3, 4})));
|
||||
EXPECT_EQ(Hash(Vector<int, 0>({})), Hash(Vector<int, 0>({})));
|
||||
EXPECT_EQ(Hash(Vector<int, 0>({1, 2, 3})), Hash(Vector<int, 0>({1, 2, 3})));
|
||||
EXPECT_NE(Hash(Vector<int, 0>({1, 2, 3})), Hash(Vector<int, 0>({1, 2, 4})));
|
||||
EXPECT_NE(Hash(Vector<int, 0>({1, 2, 3})), Hash(Vector<int, 0>({1, 2, 3, 4})));
|
||||
EXPECT_EQ(Hash(Vector<int, 3>({1, 2, 3})), Hash(Vector<int, 4>({1, 2, 3})));
|
||||
EXPECT_EQ(Hash(Vector<int, 3>({1, 2, 3})), Hash(Vector<int, 2>({1, 2, 3})));
|
||||
}
|
||||
|
|
|
@ -59,10 +59,12 @@ auto Transform(const std::vector<IN>& in, TRANSFORMER&& transform)
|
|||
/// @returns a new vector with each element of the source vector transformed by `transform`.
|
||||
template <typename IN, size_t N, typename TRANSFORMER>
|
||||
auto Transform(const Vector<IN, N>& in, TRANSFORMER&& transform)
|
||||
-> Vector<decltype(transform(in[0]))> {
|
||||
Vector<decltype(transform(in[0])), N> result(in.Length());
|
||||
for (size_t i = 0; i < result.Length(); ++i) {
|
||||
result[i] = transform(in[i]);
|
||||
-> Vector<decltype(transform(in[0])), N> {
|
||||
const auto count = in.Length();
|
||||
Vector<decltype(transform(in[0])), N> result;
|
||||
result.Reserve(count);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
result.Push(transform(in[i]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -74,9 +76,11 @@ auto Transform(const Vector<IN, N>& in, TRANSFORMER&& transform)
|
|||
template <typename IN, size_t N, typename TRANSFORMER>
|
||||
auto Transform(const Vector<IN, N>& in, TRANSFORMER&& transform)
|
||||
-> Vector<decltype(transform(in[0], 1u)), N> {
|
||||
Vector<decltype(transform(in[0], 1u)), N> result(in.Length());
|
||||
for (size_t i = 0; i < result.Length(); ++i) {
|
||||
result[i] = transform(in[i], i);
|
||||
const auto count = in.Length();
|
||||
Vector<decltype(transform(in[0], 1u)), N> result;
|
||||
result.Reserve(count);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
result.Push(transform(in[i], i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -89,9 +93,11 @@ auto Transform(const Vector<IN, N>& in, TRANSFORMER&& transform)
|
|||
template <size_t N, typename IN, typename TRANSFORMER>
|
||||
auto Transform(const VectorRef<IN>& in, TRANSFORMER&& transform)
|
||||
-> Vector<decltype(transform(in[0])), N> {
|
||||
Vector<decltype(transform(in[0])), N> result(in.Length());
|
||||
for (size_t i = 0; i < result.Length(); ++i) {
|
||||
result[i] = transform(in[i]);
|
||||
const auto count = in.Length();
|
||||
Vector<decltype(transform(in[0])), N> result;
|
||||
result.Reserve(count);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
result.Push(transform(in[i]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -104,9 +110,11 @@ auto Transform(const VectorRef<IN>& in, TRANSFORMER&& transform)
|
|||
template <size_t N, typename IN, typename TRANSFORMER>
|
||||
auto Transform(const VectorRef<IN>& in, TRANSFORMER&& transform)
|
||||
-> Vector<decltype(transform(in[0], 1u)), N> {
|
||||
Vector<decltype(transform(in[0], 1u)), N> result(in.Length());
|
||||
for (size_t i = 0; i < result.Length(); ++i) {
|
||||
result[i] = transform(in[i], i);
|
||||
const auto count = in.Length();
|
||||
Vector<decltype(transform(in[0], 1u)), N> result;
|
||||
result.Reserve(count);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
result.Push(transform(in[i], i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -119,9 +127,11 @@ auto Transform(const VectorRef<IN>& in, TRANSFORMER&& transform)
|
|||
template <size_t N, typename IN, typename TRANSFORMER>
|
||||
auto Transform(ConstVectorRef<IN> in, TRANSFORMER&& transform)
|
||||
-> Vector<decltype(transform(in[0])), N> {
|
||||
Vector<decltype(transform(in[0])), N> result(in.Length());
|
||||
for (size_t i = 0; i < result.Length(); ++i) {
|
||||
result[i] = transform(in[i]);
|
||||
const auto count = in.Length();
|
||||
Vector<decltype(transform(in[0])), N> result;
|
||||
result.Reserve(count);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
result.Push(transform(in[i]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -134,9 +144,11 @@ auto Transform(ConstVectorRef<IN> in, TRANSFORMER&& transform)
|
|||
template <size_t N, typename IN, typename TRANSFORMER>
|
||||
auto Transform(ConstVectorRef<IN> in, TRANSFORMER&& transform)
|
||||
-> Vector<decltype(transform(in[0], 1u)), N> {
|
||||
Vector<decltype(transform(in[0], 1u)), N> result(in.Length());
|
||||
for (size_t i = 0; i < result.Length(); ++i) {
|
||||
result[i] = transform(in[i], i);
|
||||
const auto count = in.Length();
|
||||
Vector<decltype(transform(in[0], 1u)), N> result;
|
||||
result.Reserve(count);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
result.Push(transform(in[i], i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "src/tint/castable.h"
|
||||
#include "src/tint/traits.h"
|
||||
#include "src/tint/utils/bitcast.h"
|
||||
|
||||
namespace tint::utils {
|
||||
|
@ -36,8 +38,6 @@ class ConstVectorRef;
|
|||
|
||||
namespace tint::utils {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// A slice represents a contigious array of elements of type T.
|
||||
template <typename T>
|
||||
struct Slice {
|
||||
|
@ -97,7 +97,42 @@ struct Slice {
|
|||
auto rend() const { return std::reverse_iterator<const T*>(begin()); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
/// 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
|
||||
/// 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
|
||||
/// `const` Castable pointers.
|
||||
template <typename TO, typename FROM>
|
||||
static constexpr bool CanReinterpretSlice =
|
||||
// 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>*`
|
||||
/// @param slice a pointer to the slice to reinterpret
|
||||
/// @returns the reinterpreted slice
|
||||
/// @see CanReinterpretSlice
|
||||
template <typename TO, typename FROM>
|
||||
const Slice<TO>* ReinterpretSlice(const Slice<FROM>* slice) {
|
||||
static_assert(CanReinterpretSlice<TO, FROM>);
|
||||
return Bitcast<const Slice<TO>*>(slice);
|
||||
}
|
||||
|
||||
/// Reinterprets `Slice<FROM>*` as `Slice<TO>*`
|
||||
/// @param slice a pointer to the slice to reinterpret
|
||||
/// @returns the reinterpreted slice
|
||||
/// @see CanReinterpretSlice
|
||||
template <typename TO, typename FROM>
|
||||
Slice<TO>* ReinterpretSlice(Slice<FROM>* slice) {
|
||||
static_assert(CanReinterpretSlice<TO, FROM>);
|
||||
return Bitcast<Slice<TO>*>(slice);
|
||||
}
|
||||
|
||||
/// Vector is a small-object-optimized, dynamically-sized vector of contigious elements of type T.
|
||||
///
|
||||
|
@ -118,39 +153,20 @@ struct Slice {
|
|||
/// array'. This reduces memory copying, but may incur additional memory usage.
|
||||
/// * Resizing, or popping elements from a vector that has spilled to a heap allocation does not
|
||||
/// revert back to using the 'small array'. Again, this is to reduce memory copying.
|
||||
template <typename T, size_t N = 0>
|
||||
template <typename T, size_t N>
|
||||
class Vector {
|
||||
public:
|
||||
/// Type of `T`.
|
||||
using value_type = T;
|
||||
/// Value of `N`
|
||||
static constexpr size_t static_length = N;
|
||||
|
||||
/// Constructor
|
||||
Vector() = default;
|
||||
|
||||
/// Constructor
|
||||
/// @param length the initial length of the vector. Elements will be zero-initialized.
|
||||
explicit Vector(size_t length) {
|
||||
Reserve(length);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
new (&impl_.slice.data[i]) T{};
|
||||
}
|
||||
impl_.slice.len = length;
|
||||
}
|
||||
|
||||
/// Constructor
|
||||
/// @param length the initial length of the vector
|
||||
/// @param value the value to copy into each element of the vector
|
||||
Vector(size_t length, const T& value) {
|
||||
Reserve(length);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
new (&impl_.slice.data[i]) T{value};
|
||||
}
|
||||
impl_.slice.len = length;
|
||||
}
|
||||
|
||||
/// Constructor
|
||||
/// @param elements the elements to place into the vector
|
||||
explicit Vector(std::initializer_list<T> elements) {
|
||||
Vector(std::initializer_list<T> elements) {
|
||||
Reserve(elements.size());
|
||||
for (auto& el : elements) {
|
||||
new (&impl_.slice.data[impl_.slice.len++]) T{el};
|
||||
|
@ -179,17 +195,32 @@ class Vector {
|
|||
MoveOrCopy(VectorRef<T>(std::move(other)));
|
||||
}
|
||||
|
||||
/// Copy constructor with covariance / const conversion
|
||||
/// @param other the vector to copy
|
||||
/// @see CanReinterpretSlice for rules about conversion
|
||||
template <typename U, size_t N2, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
||||
Vector(const Vector<U, N2>& other) { // NOLINT(runtime/explicit)
|
||||
Copy(*ReinterpretSlice<T>(&other.impl_.slice));
|
||||
}
|
||||
|
||||
/// Move constructor with covariance / const conversion
|
||||
/// @param other the vector to move
|
||||
/// @see CanReinterpretSlice for rules about conversion
|
||||
template <typename U, size_t N2, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
||||
Vector(Vector<U, N2>&& other) { // NOLINT(runtime/explicit)
|
||||
MoveOrCopy(VectorRef<T>(std::move(other)));
|
||||
}
|
||||
|
||||
/// Move constructor from a mutable vector reference
|
||||
/// @param other the vector reference to move
|
||||
Vector(VectorRef<T>&& other) { // NOLINT(runtime/explicit)
|
||||
MoveOrCopy(std::move(other));
|
||||
}
|
||||
explicit Vector(VectorRef<T>&& other) { MoveOrCopy(std::move(other)); }
|
||||
|
||||
/// Copy constructor from an immutable vector reference
|
||||
/// @param other the vector reference to copy
|
||||
Vector(const ConstVectorRef<T>& other) { // NOLINT(runtime/explicit)
|
||||
Copy(other.slice_);
|
||||
}
|
||||
explicit Vector(const ConstVectorRef<T>& other) { Copy(other.slice_); }
|
||||
|
||||
/// Move constructor from an immutable vector reference (invalid)
|
||||
Vector(ConstVectorRef<T>&&) = delete; // NOLINT(runtime/explicit)
|
||||
|
||||
/// Destructor
|
||||
~Vector() { ClearAndFree(); }
|
||||
|
@ -277,6 +308,20 @@ class Vector {
|
|||
impl_.slice.len = new_len;
|
||||
}
|
||||
|
||||
/// Resizes the vector to the given length, expanding capacity if necessary.
|
||||
/// @param new_len the new vector length
|
||||
/// @param value the value to copy into the new elements
|
||||
void Resize(size_t new_len, const T& value) {
|
||||
Reserve(new_len);
|
||||
for (size_t i = impl_.slice.len; i > new_len; i--) { // Shrink
|
||||
impl_.slice.data[i - 1].~T();
|
||||
}
|
||||
for (size_t i = impl_.slice.len; i < new_len; i++) { // Grow
|
||||
new (&impl_.slice.data[i]) T{value};
|
||||
}
|
||||
impl_.slice.len = new_len;
|
||||
}
|
||||
|
||||
/// Copies all the elements from `other` to this vector, replacing the content of this vector.
|
||||
/// @param other the
|
||||
template <typename T2, size_t N2>
|
||||
|
@ -317,7 +362,7 @@ class Vector {
|
|||
if (impl_.slice.len >= impl_.slice.cap) {
|
||||
Grow();
|
||||
}
|
||||
new (&impl_.slice.data[impl_.slice.len++]) T(std::forward<ARGS>(args)...);
|
||||
new (&impl_.slice.data[impl_.slice.len++]) T{std::forward<ARGS>(args)...};
|
||||
}
|
||||
|
||||
/// Removes and returns the last element from the vector.
|
||||
|
@ -377,7 +422,12 @@ class Vector {
|
|||
friend class ConstVectorRef;
|
||||
|
||||
/// The slice type used by this vector
|
||||
using Slice = detail::Slice<T>;
|
||||
using Slice = utils::Slice<T>;
|
||||
|
||||
template <typename... Ts>
|
||||
void AppendVariadic(Ts&&... args) {
|
||||
((new (&impl_.slice.data[impl_.slice.len++]) T(std::forward<Ts>(args))), ...);
|
||||
}
|
||||
|
||||
/// Expands the capacity of the vector
|
||||
void Grow() { Reserve(impl_.slice.cap * 2); }
|
||||
|
@ -484,6 +534,43 @@ class Vector {
|
|||
std::conditional_t<HasSmallArray, ImplWithSmallArray, ImplWithoutSmallArray> impl_;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// Helper for determining the Vector element type (`T`) from the vector's constuctor arguments
|
||||
/// @tparam IS_CASTABLE true if the types of `Ts` derive from CastableBase
|
||||
/// @tparam Ts the vector constructor argument types to infer the vector element type from.
|
||||
template <bool IS_CASTABLE, typename... Ts>
|
||||
struct VectorCommonType;
|
||||
|
||||
/// VectorCommonType specialization for non-castable types.
|
||||
template <typename... Ts>
|
||||
struct VectorCommonType</*IS_CASTABLE*/ false, Ts...> {
|
||||
/// The common T type to use for the vector
|
||||
using type = std::common_type_t<Ts...>;
|
||||
};
|
||||
|
||||
/// VectorCommonType specialization for castable types.
|
||||
template <typename... Ts>
|
||||
struct VectorCommonType</*IS_CASTABLE*/ true, Ts...> {
|
||||
/// The common Castable type (excluding pointer)
|
||||
using common_ty = CastableCommonBase<std::remove_pointer_t<Ts>...>;
|
||||
/// The common T type to use for the vector
|
||||
using type = std::conditional_t<(std::is_const_v<std::remove_pointer_t<Ts>> || ...),
|
||||
const common_ty*,
|
||||
common_ty*>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Helper for determining the Vector element type (`T`) from the vector's constuctor arguments
|
||||
template <typename... Ts>
|
||||
using VectorCommonType =
|
||||
typename detail::VectorCommonType<IsCastable<std::remove_pointer_t<Ts>...>, Ts...>::type;
|
||||
|
||||
/// Deduction guide for Vector
|
||||
template <typename... Ts>
|
||||
Vector(Ts...) -> Vector<VectorCommonType<Ts...>, sizeof...(Ts)>;
|
||||
|
||||
/// VectorRef is a weak reference to a Vector, used to pass vectors as parameters, avoiding copies
|
||||
/// between the caller and the callee. VectorRef can accept a Vector of any 'N' value, decoupling
|
||||
/// the caller's vector internal size from the callee's vector size.
|
||||
|
@ -507,16 +594,16 @@ class Vector {
|
|||
template <typename T>
|
||||
class VectorRef {
|
||||
/// The slice type used by this vector reference
|
||||
using Slice = detail::Slice<T>;
|
||||
using Slice = utils::Slice<T>;
|
||||
|
||||
public:
|
||||
/// Constructor from a Vector.
|
||||
/// @param vector the vector reference
|
||||
/// Constructor from a Vector
|
||||
/// @param vector the vector to create a reference of
|
||||
template <size_t N>
|
||||
VectorRef(Vector<T, N>& vector) // NOLINT(runtime/explicit)
|
||||
: slice_(vector.impl_.slice), can_move_(false) {}
|
||||
|
||||
/// Constructor from a std::move()'d Vector
|
||||
/// Constructor from a moved Vector
|
||||
/// @param vector the vector being moved
|
||||
template <size_t N>
|
||||
VectorRef(Vector<T, N>&& vector) // NOLINT(runtime/explicit)
|
||||
|
@ -530,6 +617,32 @@ class VectorRef {
|
|||
/// @param other the vector reference
|
||||
VectorRef(VectorRef&& other) = default;
|
||||
|
||||
/// Copy constructor with covariance / const conversion
|
||||
/// @param other the other vector reference
|
||||
template <typename U, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
||||
VectorRef(const VectorRef<U>& other) // NOLINT(runtime/explicit)
|
||||
: slice_(*ReinterpretSlice<T>(&other.slice_)), can_move_(false) {}
|
||||
|
||||
/// Move constructor with covariance / const conversion
|
||||
/// @param other the vector reference
|
||||
template <typename U, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
||||
VectorRef(VectorRef<U>&& other) // NOLINT(runtime/explicit)
|
||||
: slice_(*ReinterpretSlice<T>(&other.slice_)), can_move_(other.can_move_) {}
|
||||
|
||||
/// Constructor from a Vector with covariance / const conversion
|
||||
/// @param vector the vector to create a reference of
|
||||
/// @see CanReinterpretSlice for rules about conversion
|
||||
template <typename U, size_t N, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
||||
VectorRef(Vector<U, N>& vector) // NOLINT(runtime/explicit)
|
||||
: slice_(*ReinterpretSlice<T>(&vector.impl_.slice)), can_move_(false) {}
|
||||
|
||||
/// Constructor from a moved Vector with covariance / const conversion
|
||||
/// @param vector the vector to create a reference of
|
||||
/// @see CanReinterpretSlice for rules about conversion
|
||||
template <typename U, size_t N, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
||||
VectorRef(Vector<U, N>&& vector) // NOLINT(runtime/explicit)
|
||||
: slice_(*ReinterpretSlice<T>(&vector.impl_.slice)), can_move_(vector.impl_.CanMove()) {}
|
||||
|
||||
/// Index operator
|
||||
/// @param i the element index. Must be less than `len`.
|
||||
/// @returns a reference to the i'th element.
|
||||
|
@ -587,10 +700,18 @@ class VectorRef {
|
|||
auto rend() const { return slice_.rend(); }
|
||||
|
||||
private:
|
||||
/// Friend classes
|
||||
/// Friend class
|
||||
template <typename, size_t>
|
||||
friend class Vector;
|
||||
|
||||
/// Friend class
|
||||
template <typename>
|
||||
friend class VectorRef;
|
||||
|
||||
/// Friend class
|
||||
template <typename>
|
||||
friend class ConstVectorRef;
|
||||
|
||||
/// The slice of the vector being referenced.
|
||||
Slice& slice_;
|
||||
/// Whether the slice data is passed by r-value reference, and can be moved.
|
||||
|
@ -603,7 +724,7 @@ class VectorRef {
|
|||
template <typename T>
|
||||
class ConstVectorRef {
|
||||
/// The slice type used by this vector reference
|
||||
using Slice = detail::Slice<T>;
|
||||
using Slice = utils::Slice<T>;
|
||||
|
||||
public:
|
||||
/// Constructor from a Vector.
|
||||
|
@ -616,6 +737,34 @@ class ConstVectorRef {
|
|||
/// @param other the vector reference
|
||||
ConstVectorRef(const ConstVectorRef& other) = default;
|
||||
|
||||
/// Conversion constructor to convert from a non-const to const vector reference
|
||||
/// @param other the vector reference
|
||||
ConstVectorRef(const VectorRef<T>& other) : slice_(other.slice_) {} // NOLINT(runtime/explicit)
|
||||
|
||||
/// Move constructor. Deleted as this won't move anything.
|
||||
ConstVectorRef(ConstVectorRef&&) = delete;
|
||||
|
||||
/// Constructor from a Vector with covariance / const conversion
|
||||
/// @param vector the vector to create a reference of
|
||||
/// @see CanReinterpretSlice for rules about conversion
|
||||
template <typename U, size_t N, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
||||
ConstVectorRef(const Vector<U, N>& vector) // NOLINT(runtime/explicit)
|
||||
: slice_(*ReinterpretSlice<T>(&vector.impl_.slice)) {}
|
||||
|
||||
/// Constructor from a VectorRef with covariance / const conversion
|
||||
/// @param other the vector reference
|
||||
/// @see CanReinterpretSlice for rules about conversion
|
||||
template <typename U, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
||||
ConstVectorRef(const VectorRef<U>& other) // NOLINT(runtime/explicit)
|
||||
: slice_(*ReinterpretSlice<T>(&other.slice_)) {}
|
||||
|
||||
/// Constructor from a ConstVectorRef with covariance / const conversion
|
||||
/// @param other the vector reference
|
||||
/// @see CanReinterpretSlice for rules about conversion
|
||||
template <typename U, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
||||
ConstVectorRef(const ConstVectorRef<U>& other) // NOLINT(runtime/explicit)
|
||||
: slice_(*ReinterpretSlice<T>(&other.slice_)) {}
|
||||
|
||||
/// Index operator
|
||||
/// @param i the element index. Must be less than `len`.
|
||||
/// @returns a reference to the i'th element.
|
||||
|
@ -650,10 +799,14 @@ class ConstVectorRef {
|
|||
auto rend() const { return slice_.rend(); }
|
||||
|
||||
private:
|
||||
/// Friend classes
|
||||
/// Friend class
|
||||
template <typename, size_t>
|
||||
friend class Vector;
|
||||
|
||||
/// Friend class
|
||||
template <typename>
|
||||
friend class ConstVectorRef;
|
||||
|
||||
/// The slice of the vector being referenced.
|
||||
const Slice& slice_;
|
||||
};
|
||||
|
@ -682,14 +835,6 @@ Vector<T, N> ToVector(const std::vector<T>& vector) {
|
|||
return out;
|
||||
}
|
||||
|
||||
/// Helper for constructing a Vector from a set of elements.
|
||||
/// The returned Vector's small-array size (`N`) is equal to the number of provided elements.
|
||||
/// @param elements the elements used to construct the vector.
|
||||
template <typename T, typename... Ts>
|
||||
auto MakeVector(Ts&&... elements) {
|
||||
return Vector<T, sizeof...(Ts)>({std::forward<Ts>(elements)...});
|
||||
}
|
||||
|
||||
} // namespace tint::utils
|
||||
|
||||
#endif // SRC_TINT_UTILS_VECTOR_H_
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue