Reactor: Move print apis out of core reactor header.
This is considered non-core functionality.
Fixes: b/144686205
Change-Id: I41b811d70db9c07d26a3e6cb2f8c36a2a9e34296
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38450
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ab7064b..ae486e9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1538,16 +1538,17 @@
)
set(SUBZERO_REACTOR_LIST
- ${SOURCE_DIR}/Reactor/Reactor.cpp
- ${SOURCE_DIR}/Reactor/Reactor.hpp
- ${SOURCE_DIR}/Reactor/SubzeroReactor.cpp
- ${SOURCE_DIR}/Reactor/Optimizer.cpp
- ${SOURCE_DIR}/Reactor/Nucleus.hpp
- ${SOURCE_DIR}/Reactor/Routine.hpp
${SOURCE_DIR}/Reactor/Debug.cpp
${SOURCE_DIR}/Reactor/Debug.hpp
${SOURCE_DIR}/Reactor/ExecutableMemory.cpp
${SOURCE_DIR}/Reactor/ExecutableMemory.hpp
+ ${SOURCE_DIR}/Reactor/Nucleus.hpp
+ ${SOURCE_DIR}/Reactor/Optimizer.cpp
+ ${SOURCE_DIR}/Reactor/Print.hpp
+ ${SOURCE_DIR}/Reactor/Reactor.cpp
+ ${SOURCE_DIR}/Reactor/Reactor.hpp
+ ${SOURCE_DIR}/Reactor/Routine.hpp
+ ${SOURCE_DIR}/Reactor/SubzeroReactor.cpp
)
set(SUBZERO_INCLUDE_DIR
@@ -1670,20 +1671,21 @@
endif(REACTOR_EMIT_DEBUG_INFO)
set(REACTOR_LLVM_LIST
- ${SOURCE_DIR}/Reactor/Reactor.cpp
- ${SOURCE_DIR}/Reactor/Reactor.hpp
- ${SOURCE_DIR}/Reactor/LLVMReactor.cpp
- ${SOURCE_DIR}/Reactor/LLVMReactor.hpp
- ${SOURCE_DIR}/Reactor/LLVMReactorDebugInfo.cpp
- ${SOURCE_DIR}/Reactor/LLVMReactorDebugInfo.hpp
- ${SOURCE_DIR}/Reactor/Nucleus.hpp
- ${SOURCE_DIR}/Reactor/Routine.hpp
${SOURCE_DIR}/Reactor/CPUID.cpp
${SOURCE_DIR}/Reactor/CPUID.hpp
${SOURCE_DIR}/Reactor/Debug.cpp
${SOURCE_DIR}/Reactor/Debug.hpp
${SOURCE_DIR}/Reactor/ExecutableMemory.cpp
${SOURCE_DIR}/Reactor/ExecutableMemory.hpp
+ ${SOURCE_DIR}/Reactor/LLVMReactor.cpp
+ ${SOURCE_DIR}/Reactor/LLVMReactor.hpp
+ ${SOURCE_DIR}/Reactor/LLVMReactorDebugInfo.cpp
+ ${SOURCE_DIR}/Reactor/LLVMReactorDebugInfo.hpp
+ ${SOURCE_DIR}/Reactor/Nucleus.hpp
+ ${SOURCE_DIR}/Reactor/Print.hpp
+ ${SOURCE_DIR}/Reactor/Reactor.cpp
+ ${SOURCE_DIR}/Reactor/Reactor.hpp
+ ${SOURCE_DIR}/Reactor/Routine.hpp
)
file(GLOB_RECURSE EGL_LIST
diff --git a/src/Pipeline/SamplerCore.hpp b/src/Pipeline/SamplerCore.hpp
index b733710..e5ab898 100644
--- a/src/Pipeline/SamplerCore.hpp
+++ b/src/Pipeline/SamplerCore.hpp
@@ -17,6 +17,7 @@
#include "ShaderCore.hpp"
#include "Device/Sampler.hpp"
+#include "Reactor/Print.hpp"
#include "Reactor/Reactor.hpp"
#ifdef None
diff --git a/src/Pipeline/ShaderCore.hpp b/src/Pipeline/ShaderCore.hpp
index fd51000..aa707d5 100644
--- a/src/Pipeline/ShaderCore.hpp
+++ b/src/Pipeline/ShaderCore.hpp
@@ -15,6 +15,7 @@
#ifndef sw_ShaderCore_hpp
#define sw_ShaderCore_hpp
+#include "Reactor/Print.hpp"
#include "Reactor/Reactor.hpp"
#include "Vulkan/VkDebug.hpp"
diff --git a/src/Reactor/Print.hpp b/src/Reactor/Print.hpp
new file mode 100644
index 0000000..252e621
--- /dev/null
+++ b/src/Reactor/Print.hpp
@@ -0,0 +1,371 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef rr_Print_hpp
+#define rr_Print_hpp
+
+#if !defined(NDEBUG)
+#define ENABLE_RR_PRINT 1 // Enables RR_PRINT(), RR_WATCH()
+#endif // !defined(NDEBUG)
+
+#ifdef ENABLE_RR_PRINT
+
+#include "Reactor.hpp"
+
+#include <string>
+#include <vector>
+
+namespace rr {
+
+ // PrintValue holds the printf format and value(s) for a single argument
+ // to Print(). A single argument can be expanded into multiple printf
+ // values - for example a Float4 will expand to "%f %f %f %f" and four
+ // scalar values.
+ // The PrintValue constructor accepts the following:
+ // * Reactor LValues, RValues, Pointers.
+ // * Standard Plain-Old-Value types (int, float, bool, etc)
+ // * Custom types that specialize the PrintValue::Ty template struct.
+ // * Static arrays in the form T[N] where T can be any of the above.
+ class PrintValue
+ {
+ // Ty is a template that can be specialized for printing type T.
+ // Each specialization must expose:
+ // * A 'static std::string fmt(const T& v)' method that provides the
+ // printf format specifier.
+ // * A 'static std::vector<rr::Value*> val(const T& v)' method that
+ // returns all the printf format values.
+ template <typename T> struct Ty
+ {
+ // static std::string fmt(const T& v);
+ // static std::vector<rr::Value*> val(const T& v);
+ };
+
+ // returns the printf values for all the values in the given array.
+ template <typename T>
+ static std::vector<Value*> val(const T* list, int count) {
+ std::vector<Value*> values;
+ values.reserve(count);
+ for (int i = 0; i < count; i++)
+ {
+ auto v = val(list[i]);
+ values.insert(values.end(), v.begin(), v.end());
+ }
+ return values;
+ }
+
+ // fmt returns the comma-delimited list of printf format strings for
+ // every element in the provided list, all enclosed in square brackets.
+ template <typename T>
+ static std::string fmt(const T* list, int count)
+ {
+ std::string out = "[";
+ for (int i = 0; i < count; i++)
+ {
+ if (i > 0) { out += ", "; }
+ out += fmt(list[i]);
+ }
+ return out + "]";
+ }
+
+ static std::string addr(const void* ptr)
+ {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%p", ptr);
+ return buf;
+ }
+
+ public:
+ const std::string format;
+ const std::vector<Value*> values;
+
+ // Constructs a PrintValue for the given value.
+ template <typename T>
+ PrintValue(const T& v) : format(fmt(v)), values(val(v)) {}
+
+ // Constructs a PrintValue for the given static array.
+ template <typename T, int N>
+ PrintValue(const T (&v)[N]) : format(fmt(&v[0], N)), values(val(&v[0], N)) {}
+
+ // Constructs a PrintValue for the given array starting at arr of length
+ // len.
+ template <typename T>
+ PrintValue(const T* arr, int len) : format(fmt(arr, len)), values(val(arr, len)) {}
+
+ // PrintValue constructors for plain-old-data values.
+ PrintValue(bool v) : format(v ? "true" : "false") {}
+ PrintValue(int8_t v) : format(std::to_string(v)) {}
+ PrintValue(uint8_t v) : format(std::to_string(v)) {}
+ PrintValue(int16_t v) : format(std::to_string(v)) {}
+ PrintValue(uint16_t v) : format(std::to_string(v)) {}
+ PrintValue(int32_t v) : format(std::to_string(v)) {}
+ PrintValue(uint32_t v) : format(std::to_string(v)) {}
+ PrintValue(int64_t v) : format(std::to_string(v)) {}
+ PrintValue(uint64_t v) : format(std::to_string(v)) {}
+ PrintValue(float v) : format(std::to_string(v)) {}
+ PrintValue(double v) : format(std::to_string(v)) {}
+
+ template <typename T>
+ PrintValue(const T* v) : format(addr(v)) {}
+
+ // vals is a helper to build composite value lists.
+ // vals returns the full, sequential list of printf argument values used
+ // to print all the provided variadic values.
+ // vals() is intended to be used by implementations of
+ // PrintValue::Ty<>::vals() to help declare aggregate types.
+ // For example, if you were declaring a PrintValue::Ty<> specialization
+ // for a custom Mat4x4 matrix formed from four Vector4 values, you'd
+ // write:
+ //
+ // namespace rr
+ // {
+ // template <> struct PrintValue::Ty<Mat4x4>
+ // {
+ // static std::string fmt(const Mat4x4& v)
+ // {
+ // return "[a: <%f, %f, %f, %f>,"
+ // " b: <%f, %f, %f, %f>,"
+ // " c: <%f, %f, %f, %f>,"
+ // " d: <%f, %f, %f, %f>]";
+ // }
+ // static std::vector<rr::Value*> val(const Mat4x4& v)
+ // {
+ // return PrintValue::vals(v.a, v.b, v.c, v.d);
+ // }
+ // };
+ // }
+ template<typename ... ARGS>
+ static std::vector<Value*> vals(ARGS... v)
+ {
+ std::vector< std::vector<Value*> > lists = {val(v)...};
+ std::vector<Value*> joined;
+ for (const auto& list : lists)
+ {
+ joined.insert(joined.end(), list.begin(), list.end());
+ }
+ return joined;
+ }
+
+ // returns the printf format specifier for the given type via the
+ // PrintValue::Ty<T> specialization.
+ template <typename T>
+ static std::string fmt(const T& v) { return Ty<T>::fmt(v); }
+
+ // returns the printf value for the given type with a
+ // PrintValue::Ty<T> specialization.
+ template <typename T>
+ static std::vector<Value*> val(const T& v) { return Ty<T>::val(v); }
+ };
+
+ // PrintValue::Ty<T> specializations for basic types.
+ template <> struct PrintValue::Ty<const char*>
+ {
+ static std::string fmt(const char* v) { return "%s"; }
+ static std::vector<Value*> val(const char* v);
+ };
+ template <> struct PrintValue::Ty<std::string>
+ {
+ static std::string fmt(const std::string& v) { return PrintValue::Ty<const char*>::fmt(v.c_str()); }
+ static std::vector<Value*> val(const std::string& v) { return PrintValue::Ty<const char*>::val(v.c_str()); }
+ };
+
+ // PrintValue::Ty<T> specializations for standard Reactor types.
+ template <> struct PrintValue::Ty<Bool>
+ {
+ static std::string fmt(const RValue<Bool>& v) { return "%d"; }
+ static std::vector<Value*> val(const RValue<Bool>& v) { return {v.value}; }
+ };
+ template <> struct PrintValue::Ty<Byte>
+ {
+ static std::string fmt(const RValue<Byte>& v) { return "%d"; }
+ static std::vector<Value*> val(const RValue<Byte>& v);
+ };
+ template <> struct PrintValue::Ty<Byte4>
+ {
+ static std::string fmt(const RValue<Byte4>& v) { return "[%d, %d, %d, %d]"; }
+ static std::vector<Value*> val(const RValue<Byte4>& v);
+ };
+ template <> struct PrintValue::Ty<Int>
+ {
+ static std::string fmt(const RValue<Int>& v) { return "%d"; }
+ static std::vector<Value*> val(const RValue<Int>& v);
+ };
+ template <> struct PrintValue::Ty<Int2>
+ {
+ static std::string fmt(const RValue<Int>& v) { return "[%d, %d]"; }
+ static std::vector<Value*> val(const RValue<Int2>& v);
+ };
+ template <> struct PrintValue::Ty<Int4>
+ {
+ static std::string fmt(const RValue<Int4>& v) { return "[%d, %d, %d, %d]"; }
+ static std::vector<Value*> val(const RValue<Int4>& v);
+ };
+ template <> struct PrintValue::Ty<UInt>
+ {
+ static std::string fmt(const RValue<UInt>& v) { return "%u"; }
+ static std::vector<Value*> val(const RValue<UInt>& v);
+ };
+ template <> struct PrintValue::Ty<UInt2>
+ {
+ static std::string fmt(const RValue<UInt>& v) { return "[%u, %u]"; }
+ static std::vector<Value*> val(const RValue<UInt2>& v);
+ };
+ template <> struct PrintValue::Ty<UInt4>
+ {
+ static std::string fmt(const RValue<UInt4>& v) { return "[%u, %u, %u, %u]"; }
+ static std::vector<Value*> val(const RValue<UInt4>& v);
+ };
+ template <> struct PrintValue::Ty<Short>
+ {
+ static std::string fmt(const RValue<Short>& v) { return "%d"; }
+ static std::vector<Value*> val(const RValue<Short>& v);
+ };
+ template <> struct PrintValue::Ty<Short4>
+ {
+ static std::string fmt(const RValue<Short4>& v) { return "[%d, %d, %d, %d]"; }
+ static std::vector<Value*> val(const RValue<Short4>& v);
+ };
+ template <> struct PrintValue::Ty<UShort>
+ {
+ static std::string fmt(const RValue<UShort>& v) { return "%u"; }
+ static std::vector<Value*> val(const RValue<UShort>& v);
+ };
+ template <> struct PrintValue::Ty<UShort4>
+ {
+ static std::string fmt(const RValue<UShort4>& v) { return "[%u, %u, %u, %u]"; }
+ static std::vector<Value*> val(const RValue<UShort4>& v);
+ };
+ template <> struct PrintValue::Ty<Float>
+ {
+ static std::string fmt(const RValue<Float>& v) { return "[%f]"; }
+ static std::vector<Value*> val(const RValue<Float>& v);
+ };
+ template <> struct PrintValue::Ty<Float4>
+ {
+ static std::string fmt(const RValue<Float4>& v) { return "[%f, %f, %f, %f]"; }
+ static std::vector<Value*> val(const RValue<Float4>& v);
+ };
+ template <> struct PrintValue::Ty<Long>
+ {
+ static std::string fmt(const RValue<Long>& v) { return "%lld"; }
+ static std::vector<Value*> val(const RValue<Long>& v) { return {v.value}; }
+ };
+ template <typename T> struct PrintValue::Ty< Pointer<T> >
+ {
+ static std::string fmt(const RValue<Pointer<T>>& v) { return "%p"; }
+ static std::vector<Value*> val(const RValue<Pointer<T>>& v) { return {v.value}; }
+ };
+ template <typename T> struct PrintValue::Ty< Reference<T> >
+ {
+ static std::string fmt(const Reference<T>& v) { return PrintValue::Ty<T>::fmt(v); }
+ static std::vector<Value*> val(const Reference<T>& v) { return PrintValue::Ty<T>::val(v); }
+ };
+ template <typename T> struct PrintValue::Ty< RValue<T> >
+ {
+ static std::string fmt(const RValue<T>& v) { return PrintValue::Ty<T>::fmt(v); }
+ static std::vector<Value*> val(const RValue<T>& v) { return PrintValue::Ty<T>::val(v); }
+ };
+
+ // Printv emits a call to printf() using the function, file and line,
+ // message and optional values.
+ // See Printv below.
+ void Printv(const char* function, const char* file, int line, const char* msg, std::initializer_list<PrintValue> vals);
+
+ // Printv emits a call to printf() using the provided message and optional
+ // values.
+ // Printf replaces any bracketed indices in the message with string
+ // representations of the corresponding value in vals.
+ // For example:
+ // Printv("{0} and {1}", "red", "green");
+ // Would print the string:
+ // "red and green"
+ // Arguments can be indexed in any order.
+ // Invalid indices are not substituted.
+ inline void Printv(const char* msg, std::initializer_list<PrintValue> vals)
+ {
+ Printv(nullptr, nullptr, 0, msg, vals);
+ }
+
+ // Print is a wrapper over Printv that wraps the variadic arguments into an
+ // initializer_list before calling Printv.
+ template <typename ... ARGS>
+ void Print(const char* msg, const ARGS& ... vals) { Printv(msg, {vals...}); }
+
+ // Print is a wrapper over Printv that wraps the variadic arguments into an
+ // initializer_list before calling Printv.
+ template <typename ... ARGS>
+ void Print(const char* function, const char* file, int line, const char* msg, const ARGS& ... vals)
+ {
+ Printv(function, file, line, msg, {vals...});
+ }
+
+ // RR_LOG is a macro that calls Print(), automatically populating the
+ // function, file and line parameters and appending a newline to the string.
+ //
+ // RR_LOG() is intended to be used for debugging JIT compiled code, and is
+ // not intended for production use.
+ #if defined(_WIN32)
+ #define RR_LOG(msg, ...) Print(__FUNCSIG__, __FILE__, static_cast<int>(__LINE__), msg "\n", ##__VA_ARGS__)
+ #else
+ #define RR_LOG(msg, ...) Print(__PRETTY_FUNCTION__, __FILE__, static_cast<int>(__LINE__), msg "\n", ##__VA_ARGS__)
+ #endif
+
+ // Macro magic to perform variadic dispatch.
+ // See: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
+ // Note, this doesn't attempt to use the ##__VA_ARGS__ trick to handle 0
+ #define RR_MSVC_EXPAND_BUG(X) X // Helper macro to force expanding __VA_ARGS__ to satisfy MSVC compiler.
+ #define RR_GET_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
+ #define RR_COUNT_ARGUMENTS(...) RR_MSVC_EXPAND_BUG(RR_GET_NTH_ARG(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
+ static_assert(1 == RR_COUNT_ARGUMENTS(a), "RR_COUNT_ARGUMENTS broken"); // Sanity checks.
+ static_assert(2 == RR_COUNT_ARGUMENTS(a, b), "RR_COUNT_ARGUMENTS broken");
+ static_assert(3 == RR_COUNT_ARGUMENTS(a, b, c), "RR_COUNT_ARGUMENTS broken");
+
+ // RR_WATCH_FMT(...) resolves to a string literal that lists all the
+ // arguments by name. This string can be passed to LOG() to print each of
+ // the arguments with their name and value.
+ //
+ // RR_WATCH_FMT(...) uses the RR_COUNT_ARGUMENTS helper macro to delegate to a
+ // corresponding RR_WATCH_FMT_n specialization macro below.
+ #define RR_WATCH_CONCAT(a, b) a ## b
+ #define RR_WATCH_CONCAT2(a, b) RR_WATCH_CONCAT(a, b)
+ #define RR_WATCH_FMT(...) RR_MSVC_EXPAND_BUG(RR_WATCH_CONCAT2(RR_WATCH_FMT_, RR_COUNT_ARGUMENTS(__VA_ARGS__))(__VA_ARGS__))
+ #define RR_WATCH_FMT_1(_1) "\n " #_1 ": {0}"
+ #define RR_WATCH_FMT_2(_1, _2) RR_WATCH_FMT_1(_1) "\n " #_2 ": {1}"
+ #define RR_WATCH_FMT_3(_1, _2, _3) RR_WATCH_FMT_2(_1, _2) "\n " #_3 ": {2}"
+ #define RR_WATCH_FMT_4(_1, _2, _3, _4) RR_WATCH_FMT_3(_1, _2, _3) "\n " #_4 ": {3}"
+ #define RR_WATCH_FMT_5(_1, _2, _3, _4, _5) RR_WATCH_FMT_4(_1, _2, _3, _4) "\n " #_5 ": {4}"
+ #define RR_WATCH_FMT_6(_1, _2, _3, _4, _5, _6) RR_WATCH_FMT_5(_1, _2, _3, _4, _5) "\n " #_6 ": {5}"
+ #define RR_WATCH_FMT_7(_1, _2, _3, _4, _5, _6, _7) RR_WATCH_FMT_6(_1, _2, _3, _4, _5, _6) "\n " #_7 ": {6}"
+ #define RR_WATCH_FMT_8(_1, _2, _3, _4, _5, _6, _7, _8) RR_WATCH_FMT_7(_1, _2, _3, _4, _5, _6, _7) "\n " #_8 ": {7}"
+ #define RR_WATCH_FMT_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) RR_WATCH_FMT_8(_1, _2, _3, _4, _5, _6, _7, _8) "\n " #_9 ": {8}"
+ #define RR_WATCH_FMT_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) RR_WATCH_FMT_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) "\n " #_10 ": {9}"
+ #define RR_WATCH_FMT_11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) RR_WATCH_FMT_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) "\n " #_11 ": {10}"
+ #define RR_WATCH_FMT_12(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) RR_WATCH_FMT_11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) "\n " #_12 ": {11}"
+
+ // RR_WATCH() is a helper that prints the name and value of all the supplied
+ // arguments.
+ // For example, if you had the Int and bool variables 'foo' and 'bar' that
+ // you want to print, you can simply write:
+ // RR_WATCH(foo, bar)
+ // When this JIT compiled code is executed, it will print the string
+ // "foo: 1, bar: true" to stdout.
+ //
+ // RR_WATCH() is intended to be used for debugging JIT compiled code, and
+ // is not intended for production use.
+ #define RR_WATCH(...) RR_LOG(RR_WATCH_FMT(__VA_ARGS__), __VA_ARGS__)
+
+} // namespace rr
+
+#endif // ENABLE_RR_PRINT
+
+#endif // rr_Print_hpp
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index 5997132..e4b6be0 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -23,16 +23,11 @@
#include <cstddef>
#include <cstdio>
-#include <string>
#include <tuple>
#include <unordered_set>
#undef Bool // b/127920555
-#if !defined(NDEBUG)
-#define ENABLE_RR_PRINT 1 // Enables RR_PRINT(), RR_WATCH()
-#endif // !defined(NDEBUG)
-
#ifdef ENABLE_RR_DEBUG_INFO
// Functions used for generating JIT debug info.
// See docs/ReactorDebugInfo.md for more information.
@@ -3324,344 +3319,6 @@
// This can be used to stop an attached debugger at the given call.
void Breakpoint();
-#ifdef ENABLE_RR_PRINT
- // PrintValue holds the printf format and value(s) for a single argument
- // to Print(). A single argument can be expanded into multiple printf
- // values - for example a Float4 will expand to "%f %f %f %f" and four
- // scalar values.
- // The PrintValue constructor accepts the following:
- // * Reactor LValues, RValues, Pointers.
- // * Standard Plain-Old-Value types (int, float, bool, etc)
- // * Custom types that specialize the PrintValue::Ty template struct.
- // * Static arrays in the form T[N] where T can be any of the above.
- class PrintValue
- {
- // Ty is a template that can be specialized for printing type T.
- // Each specialization must expose:
- // * A 'static std::string fmt(const T& v)' method that provides the
- // printf format specifier.
- // * A 'static std::vector<rr::Value*> val(const T& v)' method that
- // returns all the printf format values.
- template <typename T> struct Ty
- {
- // static std::string fmt(const T& v);
- // static std::vector<rr::Value*> val(const T& v);
- };
-
- // returns the printf values for all the values in the given array.
- template <typename T>
- static std::vector<Value*> val(const T* list, int count) {
- std::vector<Value*> values;
- values.reserve(count);
- for (int i = 0; i < count; i++)
- {
- auto v = val(list[i]);
- values.insert(values.end(), v.begin(), v.end());
- }
- return values;
- }
-
- // fmt returns the comma-delimited list of printf format strings for
- // every element in the provided list, all enclosed in square brackets.
- template <typename T>
- static std::string fmt(const T* list, int count)
- {
- std::string out = "[";
- for (int i = 0; i < count; i++)
- {
- if (i > 0) { out += ", "; }
- out += fmt(list[i]);
- }
- return out + "]";
- }
-
- static std::string addr(const void* ptr)
- {
- char buf[32];
- snprintf(buf, sizeof(buf), "%p", ptr);
- return buf;
- }
-
- public:
- const std::string format;
- const std::vector<Value*> values;
-
- // Constructs a PrintValue for the given value.
- template <typename T>
- PrintValue(const T& v) : format(fmt(v)), values(val(v)) {}
-
- // Constructs a PrintValue for the given static array.
- template <typename T, int N>
- PrintValue(const T (&v)[N]) : format(fmt(&v[0], N)), values(val(&v[0], N)) {}
-
- // Constructs a PrintValue for the given array starting at arr of length
- // len.
- template <typename T>
- PrintValue(const T* arr, int len) : format(fmt(arr, len)), values(val(arr, len)) {}
-
- // PrintValue constructors for plain-old-data values.
- PrintValue(bool v) : format(v ? "true" : "false") {}
- PrintValue(int8_t v) : format(std::to_string(v)) {}
- PrintValue(uint8_t v) : format(std::to_string(v)) {}
- PrintValue(int16_t v) : format(std::to_string(v)) {}
- PrintValue(uint16_t v) : format(std::to_string(v)) {}
- PrintValue(int32_t v) : format(std::to_string(v)) {}
- PrintValue(uint32_t v) : format(std::to_string(v)) {}
- PrintValue(int64_t v) : format(std::to_string(v)) {}
- PrintValue(uint64_t v) : format(std::to_string(v)) {}
- PrintValue(float v) : format(std::to_string(v)) {}
- PrintValue(double v) : format(std::to_string(v)) {}
-
- template <typename T>
- PrintValue(const T* v) : format(addr(v)) {}
-
- // vals is a helper to build composite value lists.
- // vals returns the full, sequential list of printf argument values used
- // to print all the provided variadic values.
- // vals() is intended to be used by implementations of
- // PrintValue::Ty<>::vals() to help declare aggregate types.
- // For example, if you were declaring a PrintValue::Ty<> specialization
- // for a custom Mat4x4 matrix formed from four Vector4 values, you'd
- // write:
- //
- // namespace rr
- // {
- // template <> struct PrintValue::Ty<Mat4x4>
- // {
- // static std::string fmt(const Mat4x4& v)
- // {
- // return "[a: <%f, %f, %f, %f>,"
- // " b: <%f, %f, %f, %f>,"
- // " c: <%f, %f, %f, %f>,"
- // " d: <%f, %f, %f, %f>]";
- // }
- // static std::vector<rr::Value*> val(const Mat4x4& v)
- // {
- // return PrintValue::vals(v.a, v.b, v.c, v.d);
- // }
- // };
- // }
- template<typename ... ARGS>
- static std::vector<Value*> vals(ARGS... v)
- {
- std::vector< std::vector<Value*> > lists = {val(v)...};
- std::vector<Value*> joined;
- for (const auto& list : lists)
- {
- joined.insert(joined.end(), list.begin(), list.end());
- }
- return joined;
- }
-
- // returns the printf format specifier for the given type via the
- // PrintValue::Ty<T> specialization.
- template <typename T>
- static std::string fmt(const T& v) { return Ty<T>::fmt(v); }
-
- // returns the printf value for the given type with a
- // PrintValue::Ty<T> specialization.
- template <typename T>
- static std::vector<Value*> val(const T& v) { return Ty<T>::val(v); }
- };
-
- // PrintValue::Ty<T> specializations for basic types.
- template <> struct PrintValue::Ty<const char*>
- {
- static std::string fmt(const char* v) { return "%s"; }
- static std::vector<Value*> val(const char* v);
- };
- template <> struct PrintValue::Ty<std::string>
- {
- static std::string fmt(const std::string& v) { return PrintValue::Ty<const char*>::fmt(v.c_str()); }
- static std::vector<Value*> val(const std::string& v) { return PrintValue::Ty<const char*>::val(v.c_str()); }
- };
-
- // PrintValue::Ty<T> specializations for standard Reactor types.
- template <> struct PrintValue::Ty<Bool>
- {
- static std::string fmt(const RValue<Bool>& v) { return "%d"; }
- static std::vector<Value*> val(const RValue<Bool>& v) { return {v.value}; }
- };
- template <> struct PrintValue::Ty<Byte>
- {
- static std::string fmt(const RValue<Byte>& v) { return "%d"; }
- static std::vector<Value*> val(const RValue<Byte>& v);
- };
- template <> struct PrintValue::Ty<Byte4>
- {
- static std::string fmt(const RValue<Byte4>& v) { return "[%d, %d, %d, %d]"; }
- static std::vector<Value*> val(const RValue<Byte4>& v);
- };
- template <> struct PrintValue::Ty<Int>
- {
- static std::string fmt(const RValue<Int>& v) { return "%d"; }
- static std::vector<Value*> val(const RValue<Int>& v);
- };
- template <> struct PrintValue::Ty<Int2>
- {
- static std::string fmt(const RValue<Int>& v) { return "[%d, %d]"; }
- static std::vector<Value*> val(const RValue<Int2>& v);
- };
- template <> struct PrintValue::Ty<Int4>
- {
- static std::string fmt(const RValue<Int4>& v) { return "[%d, %d, %d, %d]"; }
- static std::vector<Value*> val(const RValue<Int4>& v);
- };
- template <> struct PrintValue::Ty<UInt>
- {
- static std::string fmt(const RValue<UInt>& v) { return "%u"; }
- static std::vector<Value*> val(const RValue<UInt>& v);
- };
- template <> struct PrintValue::Ty<UInt2>
- {
- static std::string fmt(const RValue<UInt>& v) { return "[%u, %u]"; }
- static std::vector<Value*> val(const RValue<UInt2>& v);
- };
- template <> struct PrintValue::Ty<UInt4>
- {
- static std::string fmt(const RValue<UInt4>& v) { return "[%u, %u, %u, %u]"; }
- static std::vector<Value*> val(const RValue<UInt4>& v);
- };
- template <> struct PrintValue::Ty<Short>
- {
- static std::string fmt(const RValue<Short>& v) { return "%d"; }
- static std::vector<Value*> val(const RValue<Short>& v);
- };
- template <> struct PrintValue::Ty<Short4>
- {
- static std::string fmt(const RValue<Short4>& v) { return "[%d, %d, %d, %d]"; }
- static std::vector<Value*> val(const RValue<Short4>& v);
- };
- template <> struct PrintValue::Ty<UShort>
- {
- static std::string fmt(const RValue<UShort>& v) { return "%u"; }
- static std::vector<Value*> val(const RValue<UShort>& v);
- };
- template <> struct PrintValue::Ty<UShort4>
- {
- static std::string fmt(const RValue<UShort4>& v) { return "[%u, %u, %u, %u]"; }
- static std::vector<Value*> val(const RValue<UShort4>& v);
- };
- template <> struct PrintValue::Ty<Float>
- {
- static std::string fmt(const RValue<Float>& v) { return "[%f]"; }
- static std::vector<Value*> val(const RValue<Float>& v);
- };
- template <> struct PrintValue::Ty<Float4>
- {
- static std::string fmt(const RValue<Float4>& v) { return "[%f, %f, %f, %f]"; }
- static std::vector<Value*> val(const RValue<Float4>& v);
- };
- template <> struct PrintValue::Ty<Long>
- {
- static std::string fmt(const RValue<Long>& v) { return "%lld"; }
- static std::vector<Value*> val(const RValue<Long>& v) { return {v.value}; }
- };
- template <typename T> struct PrintValue::Ty< Pointer<T> >
- {
- static std::string fmt(const RValue<Pointer<T>>& v) { return "%p"; }
- static std::vector<Value*> val(const RValue<Pointer<T>>& v) { return {v.value}; }
- };
- template <typename T> struct PrintValue::Ty< Reference<T> >
- {
- static std::string fmt(const Reference<T>& v) { return PrintValue::Ty<T>::fmt(v); }
- static std::vector<Value*> val(const Reference<T>& v) { return PrintValue::Ty<T>::val(v); }
- };
- template <typename T> struct PrintValue::Ty< RValue<T> >
- {
- static std::string fmt(const RValue<T>& v) { return PrintValue::Ty<T>::fmt(v); }
- static std::vector<Value*> val(const RValue<T>& v) { return PrintValue::Ty<T>::val(v); }
- };
-
- // Printv emits a call to printf() using the function, file and line,
- // message and optional values.
- // See Printv below.
- void Printv(const char* function, const char* file, int line, const char* msg, std::initializer_list<PrintValue> vals);
-
- // Printv emits a call to printf() using the provided message and optional
- // values.
- // Printf replaces any bracketed indices in the message with string
- // representations of the corresponding value in vals.
- // For example:
- // Printv("{0} and {1}", "red", "green");
- // Would print the string:
- // "red and green"
- // Arguments can be indexed in any order.
- // Invalid indices are not substituted.
- inline void Printv(const char* msg, std::initializer_list<PrintValue> vals)
- {
- Printv(nullptr, nullptr, 0, msg, vals);
- }
-
- // Print is a wrapper over Printv that wraps the variadic arguments into an
- // initializer_list before calling Printv.
- template <typename ... ARGS>
- void Print(const char* msg, const ARGS& ... vals) { Printv(msg, {vals...}); }
-
- // Print is a wrapper over Printv that wraps the variadic arguments into an
- // initializer_list before calling Printv.
- template <typename ... ARGS>
- void Print(const char* function, const char* file, int line, const char* msg, const ARGS& ... vals)
- {
- Printv(function, file, line, msg, {vals...});
- }
-
- // RR_LOG is a macro that calls Print(), automatically populating the
- // function, file and line parameters and appending a newline to the string.
- //
- // RR_LOG() is intended to be used for debugging JIT compiled code, and is
- // not intended for production use.
- #if defined(_WIN32)
- #define RR_LOG(msg, ...) Print(__FUNCSIG__, __FILE__, static_cast<int>(__LINE__), msg "\n", ##__VA_ARGS__)
- #else
- #define RR_LOG(msg, ...) Print(__PRETTY_FUNCTION__, __FILE__, static_cast<int>(__LINE__), msg "\n", ##__VA_ARGS__)
- #endif
-
- // Macro magic to perform variadic dispatch.
- // See: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
- // Note, this doesn't attempt to use the ##__VA_ARGS__ trick to handle 0
- #define RR_MSVC_EXPAND_BUG(X) X // Helper macro to force expanding __VA_ARGS__ to satisfy MSVC compiler.
- #define RR_GET_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
- #define RR_COUNT_ARGUMENTS(...) RR_MSVC_EXPAND_BUG(RR_GET_NTH_ARG(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
- static_assert(1 == RR_COUNT_ARGUMENTS(a), "RR_COUNT_ARGUMENTS broken"); // Sanity checks.
- static_assert(2 == RR_COUNT_ARGUMENTS(a, b), "RR_COUNT_ARGUMENTS broken");
- static_assert(3 == RR_COUNT_ARGUMENTS(a, b, c), "RR_COUNT_ARGUMENTS broken");
-
- // RR_WATCH_FMT(...) resolves to a string literal that lists all the
- // arguments by name. This string can be passed to LOG() to print each of
- // the arguments with their name and value.
- //
- // RR_WATCH_FMT(...) uses the RR_COUNT_ARGUMENTS helper macro to delegate to a
- // corresponding RR_WATCH_FMT_n specialization macro below.
- #define RR_WATCH_CONCAT(a, b) a ## b
- #define RR_WATCH_CONCAT2(a, b) RR_WATCH_CONCAT(a, b)
- #define RR_WATCH_FMT(...) RR_MSVC_EXPAND_BUG(RR_WATCH_CONCAT2(RR_WATCH_FMT_, RR_COUNT_ARGUMENTS(__VA_ARGS__))(__VA_ARGS__))
- #define RR_WATCH_FMT_1(_1) "\n " #_1 ": {0}"
- #define RR_WATCH_FMT_2(_1, _2) RR_WATCH_FMT_1(_1) "\n " #_2 ": {1}"
- #define RR_WATCH_FMT_3(_1, _2, _3) RR_WATCH_FMT_2(_1, _2) "\n " #_3 ": {2}"
- #define RR_WATCH_FMT_4(_1, _2, _3, _4) RR_WATCH_FMT_3(_1, _2, _3) "\n " #_4 ": {3}"
- #define RR_WATCH_FMT_5(_1, _2, _3, _4, _5) RR_WATCH_FMT_4(_1, _2, _3, _4) "\n " #_5 ": {4}"
- #define RR_WATCH_FMT_6(_1, _2, _3, _4, _5, _6) RR_WATCH_FMT_5(_1, _2, _3, _4, _5) "\n " #_6 ": {5}"
- #define RR_WATCH_FMT_7(_1, _2, _3, _4, _5, _6, _7) RR_WATCH_FMT_6(_1, _2, _3, _4, _5, _6) "\n " #_7 ": {6}"
- #define RR_WATCH_FMT_8(_1, _2, _3, _4, _5, _6, _7, _8) RR_WATCH_FMT_7(_1, _2, _3, _4, _5, _6, _7) "\n " #_8 ": {7}"
- #define RR_WATCH_FMT_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) RR_WATCH_FMT_8(_1, _2, _3, _4, _5, _6, _7, _8) "\n " #_9 ": {8}"
- #define RR_WATCH_FMT_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) RR_WATCH_FMT_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) "\n " #_10 ": {9}"
- #define RR_WATCH_FMT_11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) RR_WATCH_FMT_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) "\n " #_11 ": {10}"
- #define RR_WATCH_FMT_12(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) RR_WATCH_FMT_11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) "\n " #_12 ": {11}"
-
- // RR_WATCH() is a helper that prints the name and value of all the supplied
- // arguments.
- // For example, if you had the Int and bool variables 'foo' and 'bar' that
- // you want to print, you can simply write:
- // RR_WATCH(foo, bar)
- // When this JIT compiled code is executed, it will print the string
- // "foo: 1, bar: true" to stdout.
- //
- // RR_WATCH() is intended to be used for debugging JIT compiled code, and
- // is not intended for production use.
- #define RR_WATCH(...) RR_LOG(RR_WATCH_FMT(__VA_ARGS__), __VA_ARGS__)
-#endif // ENABLE_RR_PRINT
-
class ForData
{
public:
diff --git a/src/Reactor/Reactor.vcxproj b/src/Reactor/Reactor.vcxproj
index 9859409..4f6ef61 100644
--- a/src/Reactor/Reactor.vcxproj
+++ b/src/Reactor/Reactor.vcxproj
@@ -300,6 +300,7 @@
<ClInclude Include="ExecutableMemory.hpp" />
<ClInclude Include="MutexLock.hpp" />
<ClInclude Include="Nucleus.hpp" />
+ <ClInclude Include="Print.hpp" />
<ClInclude Include="Reactor.hpp" />
<ClInclude Include="Routine.hpp" />
<ClInclude Include="Thread.hpp" />
diff --git a/src/Reactor/Reactor.vcxproj.filters b/src/Reactor/Reactor.vcxproj.filters
index 32900aa..22c1a6b 100644
--- a/src/Reactor/Reactor.vcxproj.filters
+++ b/src/Reactor/Reactor.vcxproj.filters
@@ -41,6 +41,9 @@
<ClInclude Include="Nucleus.hpp">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="Print.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="Reactor.hpp">
<Filter>Header Files</Filter>
</ClInclude>