// Copyright 2023 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_DAWN_NATIVE_CHAINUTILS_H_ #define SRC_DAWN_NATIVE_CHAINUTILS_H_ #include <bitset> #include <string> #include <tuple> #include <type_traits> #include "absl/strings/str_format.h" #include "dawn/common/Math.h" #include "dawn/native/ChainUtils_autogen.h" #include "dawn/native/Error.h" namespace dawn::native { namespace detail { // Gets the chain type for an extensible type. template <typename T> struct ChainTypeFor { … }; } // namespace detail template <typename T> class UnpackedPtr; namespace detail { // Converts to the expected pointer types depending on the extensibility of the structure. template <typename UnpackedPtrT, typename U> struct PtrTypeFor; PtrTypeFor<UnpackedPtr<T>, U>; } // namespace detail // Unpacks chained structures in a best effort manner (skipping unknown chains) without applying // validation. If the same structure is duplicated in the chain, it is unspecified which one the // result of Get will be. These are the effective constructors for the wrapper types. Note that // these are implemented in the generated ChainUtils_autogen.cpp file. template <typename T, typename = std::enable_if_t<detail::ExtensibilityFor<T> == detail::Extensibility::In>> UnpackedPtr<T> Unpack(const T* chain); template <typename T, typename = std::enable_if_t<detail::ExtensibilityFor<T> == detail::Extensibility::Out>> UnpackedPtr<T> Unpack(T* chain); // Unpacks chained structures into UnpackedPtr<T> while applying validation. template <typename T, typename = std::enable_if_t<detail::ExtensibilityFor<T> == detail::Extensibility::In>> ResultOrError<UnpackedPtr<T>> ValidateAndUnpack(const T* chain); template <typename T, typename = std::enable_if_t<detail::ExtensibilityFor<T> == detail::Extensibility::Out>> ResultOrError<UnpackedPtr<T>> ValidateAndUnpack(T* chain); // // Wrapper class for unpacked pointers. The classes essentially acts like a const T* or T* with // the additional capabilities to validate and retrieve chained structures. // template <typename T> class UnpackedPtr { … }; // Tuple type of a Branch and an optional list of corresponding Extensions. template <typename B, typename... Exts> struct Branch; // ------------------------------------------------------------------------------------------------ // Implementation details start here so that the headers are terse. // ------------------------------------------------------------------------------------------------ namespace detail { // Helpers to get the index in an unpacked tuple type for a particular type. UnpackedPtrTupleIndexOf; UnpackedPtrTupleIndexOf; UnpackedPtrTupleIndexOf; UnpackedPtrIndexOf; UnpackedPtrIndexOf; // Currently using an internal 64-bit unsigned int for internal representation. This is necessary // because std::bitset::operator| is not constexpr until C++23. UnpackedPtrBitsetForExts; UnpackedPtrBitsetForExts; template <typename UnpackedPtrT, typename...> struct OneBranchValidator; OneBranchValidator<UnpackedPtrT, Branch<R, Exts...>>; template <typename UnpackedPtrT, typename... Branches> struct BranchesValidator { … }; template <typename UnpackedPtrT, typename... Allowed> struct SubsetValidator { … }; } // namespace detail template <typename T> template <typename In> auto UnpackedPtr<T>::Get() const { … } template <typename T> bool UnpackedPtr<T>::Empty() const { … } template <typename T> std::string UnpackedPtr<T>::ToString() const { … } // Validates that an unpacked chain retrieved via ValidateAndUnpack matches a valid "branch", // where a "branch" is defined as a required "root" extension and optional follow-up // extensions. // // Returns the wgpu::SType associated with the "root" extension of a "branch" if matched, // otherwise returns an error. // // Example usage: // UnpackedPtr<T> u; // DAWN_TRY_ASSIGN(u, ValidateAndUnpack(desc)); // wgpu::SType rootType; // DAWN_TRY_ASSIGN(rootType, // u.ValidateBranches<Branch<Root1>, Branch<Root2, R2Ext1>>()); // switch (rootType) { // case Root1: { // <do something> // } // case Root2: { // R2Ext1 ext = u.Get<R2Ext1>(u); // if (ext) { // <do something with optional extension(s)> // } // } // default: // DAWN_UNREACHABLE(); // } // // The example above checks that the unpacked chain is either: // - only a Root1 extension // - or a Root2 extension with an optional R2Ext1 extension // Any other configuration is deemed invalid. template <typename T> template <typename... Branches> ResultOrError<wgpu::SType> UnpackedPtr<T>::ValidateBranches() const { … } // Validates that an unpacked chain retrieved via ValidateAndUnpack contains a subset of the // Allowed extensions. If there are any other extensions, returns an error. // // Example usage: // UnpackedPtr<T> u; // DAWN_TRY_ASSIGN(u, ValidateAndUnpack(desc)); // DAWN_TRY(u.ValidateSubset<Ext1>()); // // Even though "valid" extensions on descriptor may include both Ext1 and Ext2, ValidateSubset // will further enforce that Ext2 is not on the chain in the example above. template <typename T> template <typename... Allowed> MaybeError UnpackedPtr<T>::ValidateSubset() const { … } } // namespace dawn::native #endif // SRC_DAWN_NATIVE_CHAINUTILS_H_