1 // Copyright 2021 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef DAWNNODE_UTILS_DEBUG_H_ 16 #define DAWNNODE_UTILS_DEBUG_H_ 17 18 #include <iostream> 19 #include <optional> 20 #include <sstream> 21 #include <unordered_map> 22 #include <variant> 23 #include <vector> 24 25 #include "dawn/webgpu_cpp_print.h" 26 27 namespace wgpu { namespace utils { 28 29 // Write() is a helper for printing container types to the std::ostream. 30 // Write() is used by the LOG() macro below. 31 32 // Forward declarations Write(std::ostream & out)33 inline std::ostream& Write(std::ostream& out) { 34 return out; 35 } 36 template <typename T> 37 inline std::ostream& Write(std::ostream& out, const std::optional<T>& value); 38 template <typename T> 39 inline std::ostream& Write(std::ostream& out, const std::vector<T>& value); 40 template <typename K, typename V> 41 inline std::ostream& Write(std::ostream& out, const std::unordered_map<K, V>& value); 42 template <typename... TYS> 43 inline std::ostream& Write(std::ostream& out, const std::variant<TYS...>& value); 44 template <typename VALUE> 45 std::ostream& Write(std::ostream& out, VALUE&& value); 46 47 // Write() implementations 48 template <typename T> Write(std::ostream & out,const std::optional<T> & value)49 std::ostream& Write(std::ostream& out, const std::optional<T>& value) { 50 if (value.has_value()) { 51 return Write(out, value.value()); 52 } 53 return out << "<undefined>"; 54 } 55 56 template <typename T> Write(std::ostream & out,const std::vector<T> & value)57 std::ostream& Write(std::ostream& out, const std::vector<T>& value) { 58 out << "["; 59 bool first = true; 60 for (const auto& el : value) { 61 if (!first) { 62 out << ", "; 63 } 64 first = false; 65 Write(out, el); 66 } 67 return out << "]"; 68 } 69 70 template <typename K, typename V> Write(std::ostream & out,const std::unordered_map<K,V> & value)71 std::ostream& Write(std::ostream& out, const std::unordered_map<K, V>& value) { 72 out << "{"; 73 bool first = true; 74 for (auto it : value) { 75 if (!first) { 76 out << ", "; 77 } 78 first = false; 79 Write(out, it.first); 80 out << ": "; 81 Write(out, it.second); 82 } 83 return out << "}"; 84 } 85 86 template <typename... TYS> Write(std::ostream & out,const std::variant<TYS...> & value)87 std::ostream& Write(std::ostream& out, const std::variant<TYS...>& value) { 88 std::visit([&](auto&& v) { Write(out, v); }, value); 89 return out; 90 } 91 92 template <typename VALUE> Write(std::ostream & out,VALUE && value)93 std::ostream& Write(std::ostream& out, VALUE&& value) { 94 return out << std::forward<VALUE>(value); 95 } 96 97 template <typename FIRST, typename... REST> Write(std::ostream & out,FIRST && first,REST &&...rest)98 inline std::ostream& Write(std::ostream& out, FIRST&& first, REST&&... rest) { 99 Write(out, std::forward<FIRST>(first)); 100 Write(out, std::forward<REST>(rest)...); 101 return out; 102 } 103 104 // Fatal() prints a message to stdout with the given file, line, function and optional message, 105 // then calls abort(). Fatal() is usually not called directly, but by the UNREACHABLE() and 106 // UNIMPLEMENTED() macro below. 107 template <typename... MSG_ARGS> Fatal(const char * reason,const char * file,int line,const char * function,MSG_ARGS &&...msg_args)108 [[noreturn]] inline void Fatal(const char* reason, 109 const char* file, 110 int line, 111 const char* function, 112 MSG_ARGS&&... msg_args) { 113 std::stringstream msg; 114 msg << file << ":" << line << ": " << reason << ": " << function << "()"; 115 if constexpr (sizeof...(msg_args) > 0) { 116 msg << " "; 117 Write(msg, std::forward<MSG_ARGS>(msg_args)...); 118 } 119 std::cout << msg.str() << std::endl; 120 abort(); 121 } 122 123 // LOG() prints the current file, line and function to stdout, followed by a 124 // string representation of all the variadic arguments. 125 #define LOG(...) \ 126 ::wgpu::utils::Write(std::cout << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__ << ": ", \ 127 ##__VA_ARGS__) \ 128 << std::endl 129 130 // UNIMPLEMENTED() prints 'UNIMPLEMENTED' with the current file, line and 131 // function to stdout, along with the optional message, then calls abort(). 132 // The macro calls Fatal(), which is annotated with [[noreturn]]. 133 // Used to stub code that has not yet been implemented. 134 #define UNIMPLEMENTED(...) \ 135 ::wgpu::utils::Fatal("UNIMPLEMENTED", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__) 136 137 // UNREACHABLE() prints 'UNREACHABLE' with the current file, line and 138 // function to stdout, along with the optional message, then calls abort(). 139 // The macro calls Fatal(), which is annotated with [[noreturn]]. 140 // Used to stub code that has not yet been implemented. 141 #define UNREACHABLE(...) \ 142 ::wgpu::utils::Fatal("UNREACHABLE", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__) 143 144 }} // namespace wgpu::utils 145 146 #endif // DAWNNODE_UTILS_DEBUG_H_ 147