// Copyright 2022 The Dawn & Tint Authors // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef SRC_TINT_UTILS_CONTAINERS_VECTOR_H_ #define SRC_TINT_UTILS_CONTAINERS_VECTOR_H_ #include <stddef.h> #include <stdint.h> #include <algorithm> #include <atomic> #include <iterator> #include <new> #include <utility> #include <vector> #include "src/tint/utils/containers/slice.h" #include "src/tint/utils/ice/ice.h" #include "src/tint/utils/macros/compiler.h" #include "src/tint/utils/math/hash.h" #include "src/tint/utils/memory/aligned_storage.h" #include "src/tint/utils/memory/bitcast.h" #ifndef TINT_VECTOR_MUTATION_CHECKS_ENABLED #ifdef NDEBUG #define TINT_VECTOR_MUTATION_CHECKS_ENABLED … #else #define TINT_VECTOR_MUTATION_CHECKS_ENABLED … #endif #endif #if TINT_VECTOR_MUTATION_CHECKS_ENABLED #define TINT_VECTOR_MUTATION_CHECK_ASSERT(x) … #else #define TINT_VECTOR_MUTATION_CHECK_ASSERT … #endif /// Forward declarations namespace tint { template <typename> class VectorRef; } // namespace tint namespace tint { /// VectorIterator is a forward iterator of Vector elements. template <typename T, bool FORWARD = true> class VectorIterator { … }; /// @param out the stream to write to /// @param it the VectorIterator /// @returns @p out so calls can be chained template <typename STREAM, typename T, bool FORWARD, typename = traits::EnableIfIsOStream<STREAM>> auto& operator<<(STREAM& out, const VectorIterator<T, FORWARD>& it) { … } /// Vector is a small-object-optimized, dynamically-sized vector of contigious elements of type T. /// /// Vector will fit `N` elements internally before spilling to heap allocations. If `N` is greater /// than zero, the internal elements are stored in a 'small array' held internally by the Vector. /// /// Vectors can be copied or moved. /// /// Copying a vector will either copy to the 'small array' if the number of elements is equal to or /// less than N, otherwise elements will be copied into a new heap allocation. /// /// Moving a vector will reassign ownership of the heap-allocation memory, if the source vector /// holds its elements in a heap allocation, otherwise a copy will be made as described above. /// /// Vector is optimized for CPU performance over memory efficiency. For example: /// * Moving a vector that stores its elements in a heap allocation to another vector will simply /// assign the heap allocation, even if the target vector can hold the elements in its 'small /// 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> class Vector { … }; 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. VectorCommonType<false, Ts...>; /// VectorCommonType specialization for castable types. VectorCommonType<true, Ts...>; } // namespace detail /// Helper for determining the Vector element type (`T`) from the vector's constuctor arguments VectorCommonType; /// 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, or as an non-static sized accessor on a vector. VectorRef can /// accept a Vector of any 'N' value, decoupling the caller's vector internal size from the callee's /// vector size. A VectorRef tracks the usage of moves either side of the call. If at the call site, /// a Vector argument is moved to a VectorRef parameter, and within the callee, the VectorRef /// parameter is moved to a Vector, then the Vector heap allocation will be moved. For example: /// /// ``` /// void func_a() { /// Vector<std::string, 4> vec; /// // logic to populate 'vec'. /// func_b(std::move(vec)); // Constructs a VectorRef tracking the move here. /// } /// /// void func_b(VectorRef<std::string> vec_ref) { /// // A move was made when calling func_b, so the vector can be moved instead of copied. /// Vector<std::string, 2> vec(std::move(vec_ref)); /// } /// ``` /// /// Aside from this move pattern, a VectorRef provides an immutable reference to the Vector. template <typename T> class VectorRef { … }; /// Helper for converting a Vector to a std::vector. /// @param vector the input vector /// @return the converted vector /// @note This helper exists to help code migration. Avoid if possible. template <typename T, size_t N> std::vector<T> ToStdVector(const Vector<T, N>& vector) { … } /// Helper for converting a std::vector to a Vector. /// @param vector the input vector /// @return the converted vector /// @note This helper exists to help code migration. Avoid if possible. template <typename T, size_t N = 0> Vector<T, N> ToVector(const std::vector<T>& vector) { … } /// Prints the vector @p vec to @p o /// @param o the stream to write to /// @param vec the vector /// @return the stream so calls can be chained template <typename STREAM, typename T, size_t N, typename = traits::EnableIfIsOStream<STREAM>> auto& operator<<(STREAM& o, const Vector<T, N>& vec) { … } /// Prints the vector @p vec to @p o /// @param o the stream to write to /// @param vec the vector reference /// @return the stream so calls can be chained template <typename STREAM, typename T, typename = traits::EnableIfIsOStream<STREAM>> auto& operator<<(STREAM& o, VectorRef<T> vec) { … } namespace detail { /// IsVectorLike<T>::value is true if T is a Vector or VectorRef. template <typename T> struct IsVectorLike { … }; /// IsVectorLike specialization for Vector IsVectorLike<Vector<T, N>>; /// IsVectorLike specialization for VectorRef IsVectorLike<VectorRef<T>>; } // namespace detail /// True if T is a Vector<T, N> or VectorRef<T> IsVectorLike; } // namespace tint #endif // SRC_TINT_UTILS_CONTAINERS_VECTOR_H_