| /////////////////////////////////////////////////////////////////////////////// |
| // // |
| // DumpContext.h // |
| // Copyright (C) Microsoft Corporation. All rights reserved. // |
| // This file is distributed under the University of Illinois Open Source // |
| // License. See LICENSE.TXT for details. // |
| // // |
| // Context for dumping structured data, enums, and flags for use in tests. // |
| // // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #pragma once |
| |
| #include "dxc/Support/Global.h" |
| #include "dxc/Test/D3DReflectionStrings.h" |
| #include <iomanip> |
| #include <ostream> |
| #include <sstream> |
| #include <string> |
| #include <unordered_set> |
| |
| namespace hlsl { |
| using namespace RDAT; |
| namespace dump { |
| |
| template <typename _T> struct EnumValue { |
| public: |
| EnumValue(const _T &e) : eValue(e) {} |
| _T eValue; |
| }; |
| |
| template <typename _T, typename _StoreT = uint32_t> struct FlagsValue { |
| public: |
| FlagsValue(const _StoreT &f) : Flags(f) {} |
| _StoreT Flags; |
| }; |
| |
| struct QuotedStringValue { |
| public: |
| QuotedStringValue(const char *str) : Str(str) {} |
| const char *Str; |
| }; |
| |
| class DumpContext { |
| private: |
| std::ostream &m_out; |
| unsigned m_indent = 0; |
| std::unordered_set<size_t> m_visited; |
| |
| std::ostream &DoIndent() { |
| return m_out << std::setfill(' ') |
| << std::setw((m_indent > 16) ? 32 : m_indent * 2) << ""; |
| } |
| |
| public: |
| DumpContext(std::ostream &outStream) : m_out(outStream) {} |
| |
| void Indent() { |
| if (m_indent < (1 << 30)) |
| m_indent++; |
| } |
| void Dedent() { |
| if (m_indent > 0) |
| m_indent--; |
| } |
| |
| template <typename _T> std::ostream &Write(_T t) { return Write(m_out, t); } |
| template <typename _T, typename... Args> |
| std::ostream &Write(_T t, Args... args) { |
| return Write(Write(m_out, t), args...); |
| } |
| template <typename _T> std::ostream &Write(std::ostream &out, _T t) { |
| return out << t; |
| } |
| template <typename _T, typename... Args> |
| std::ostream &Write(std::ostream &out, _T t, Args... args) { |
| return Write(Write(out, t), args...); |
| } |
| |
| template <typename _T> std::ostream &WriteLn(_T t) { |
| return Write(DoIndent(), t) << std::endl |
| << std::resetiosflags(std::ios_base::basefield | |
| std::ios_base::showbase); |
| } |
| template <typename _T, typename... Args> |
| std::ostream &WriteLn(_T t, Args... args) { |
| return Write(Write(DoIndent(), t), args...) |
| << std::endl |
| << std::resetiosflags(std::ios_base::basefield | |
| std::ios_base::showbase); |
| } |
| |
| template <typename _T> std::ostream &WriteEnumValue(_T eValue) { |
| const char *szValue = ToString(eValue); |
| if (szValue) |
| return Write(szValue); |
| else |
| return Write("<unknown: ", std::hex, std::showbase, (UINT)eValue, ">"); |
| } |
| |
| template <typename _T> void DumpEnum(const char *Name, _T eValue) { |
| WriteLn(Name, ": ", EnumValue<_T>(eValue)); |
| } |
| template <typename _T, typename _StoreT = uint32_t> |
| void DumpFlags(const char *Name, _StoreT Flags) { |
| WriteLn(Name, ": ", FlagsValue<_T, _StoreT>(Flags)); |
| } |
| |
| template <typename... Args> void Failure(Args... args) { |
| WriteLn("Failed: ", args...); |
| } |
| |
| // Return true if ptr has not yet been visited, prevents recursive dumping |
| bool Visit(size_t value) { return m_visited.insert(value).second; } |
| bool Visit(const void *ptr) { return ptr ? Visit((size_t)ptr) : false; } |
| void VisitReset() { m_visited.clear(); } |
| }; |
| |
| template <> |
| inline std::ostream &DumpContext::Write<uint8_t>(std::ostream &out, uint8_t t) { |
| return out << (unsigned)t; |
| } |
| |
| // Copied from llvm/ADT/StringExtras.h |
| inline char hexdigit(unsigned X, bool LowerCase = false) { |
| const char HexChar = LowerCase ? 'a' : 'A'; |
| return X < 10 ? '0' + X : HexChar + X - 10; |
| } |
| // Copied from lib/IR/AsmWriter.cpp |
| // EscapedString - Print each character of the specified string, escaping |
| // it if it is not printable or if it is an escape char. |
| inline std::string EscapedString(const char *text) { |
| std::ostringstream ss; |
| size_t size = strlen(text); |
| for (unsigned i = 0, e = size; i != e; ++i) { |
| unsigned char C = text[i]; |
| if (isprint(C) && C != '\\' && C != '"') |
| ss << C; |
| else |
| ss << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F); |
| } |
| return ss.str(); |
| } |
| |
| template <typename _T> |
| std::ostream &operator<<(std::ostream &out, const EnumValue<_T> &obj) { |
| if (const char *szValue = ToString(obj.eValue)) |
| return out << szValue; |
| else |
| return out << "<unknown: " << std::hex << std::showbase << (UINT)obj.eValue |
| << ">"; |
| } |
| |
| template <typename _T, typename _StoreT> |
| std::ostream &operator<<(std::ostream &out, |
| const FlagsValue<_T, _StoreT> &obj) { |
| _StoreT Flags = obj.Flags; |
| if (!Flags) { |
| const char *szValue = ToString((_T)0); |
| if (szValue) |
| return out << "0 (" << szValue << ")"; |
| else |
| return out << "0"; |
| } |
| uint32_t flag = 0; |
| out << "("; |
| while (Flags) { |
| if (flag) |
| out << " | "; |
| flag = (Flags & ~(Flags - 1)); |
| Flags ^= flag; |
| out << EnumValue<_T>((_T)flag); |
| } |
| out << ")"; |
| return out; |
| } |
| |
| inline std::ostream &operator<<(std::ostream &out, |
| const QuotedStringValue &obj) { |
| if (!obj.Str) |
| return out << "<null string pointer>"; |
| return out << "\"" << EscapedString(obj.Str) << "\""; |
| } |
| |
| } // namespace dump |
| } // namespace hlsl |