#if defined(ASTCENC_DIAGNOSTICS)
#include <cassert>
#include <cstdarg>
#include <cstdio>
#include <cmath>
#include <limits>
#include <string>
#include "astcenc_diagnostic_trace.h"
static TraceLog* g_TraceLog = nullptr;
static const size_t g_trace_indent = 2;
TraceLog::TraceLog(
const char* file_name):
m_file(file_name, std::ofstream::out | std::ofstream::binary)
{
assert(!g_TraceLog);
g_TraceLog = this;
m_root = new TraceNode("root");
}
TraceNode* TraceLog::get_current_leaf()
{
if (m_stack.size())
{
return m_stack.back();
}
return nullptr;
}
size_t TraceLog::get_depth()
{
return m_stack.size();
}
TraceLog::~TraceLog()
{
assert(g_TraceLog == this);
delete m_root;
g_TraceLog = nullptr;
}
TraceNode::TraceNode(
const char* format,
...
) {
constexpr size_t bufsz = 256;
char buffer[bufsz];
va_list args;
va_start (args, format);
vsnprintf (buffer, bufsz, format, args);
va_end (args);
buffer[bufsz - 1] = 0;
TraceNode* parent = g_TraceLog->get_current_leaf();
size_t depth = g_TraceLog->get_depth();
g_TraceLog->m_stack.push_back(this);
bool comma = parent && parent->m_attrib_count;
auto& out = g_TraceLog->m_file;
if (parent)
{
parent->m_attrib_count++;
}
if (comma)
{
out << ',';
}
if (depth)
{
out << '\n';
}
size_t out_indent = (depth * 2) * g_trace_indent;
size_t in_indent = (depth * 2 + 1) * g_trace_indent;
std::string out_indents("");
if (out_indent)
{
out_indents = std::string(out_indent, ' ');
}
std::string in_indents(in_indent, ' ');
out << out_indents << "[ \"node\", \"" << buffer << "\",\n";
out << in_indents << "[";
}
void TraceNode::add_attrib(
std::string type,
std::string key,
std::string value
) {
(void)type;
size_t depth = g_TraceLog->get_depth();
size_t indent = (depth * 2) * g_trace_indent;
auto& out = g_TraceLog->m_file;
bool comma = m_attrib_count;
m_attrib_count++;
if (comma)
{
out << ',';
}
out << '\n';
out << std::string(indent, ' ') << "[ "
<< "\"" << key << "\", "
<< value << " ]";
}
TraceNode::~TraceNode()
{
g_TraceLog->m_stack.pop_back();
auto& out = g_TraceLog->m_file;
size_t depth = g_TraceLog->get_depth();
size_t out_indent = (depth * 2) * g_trace_indent;
size_t in_indent = (depth * 2 + 1) * g_trace_indent;
std::string out_indents("");
if (out_indent)
{
out_indents = std::string(out_indent, ' ');
}
std::string in_indents(in_indent, ' ');
if (m_attrib_count)
{
out << "\n" << in_indents;
}
out << "]\n";
out << out_indents << "]";
}
void trace_add_data(
const char* key,
const char* format,
...
) {
constexpr size_t bufsz = 256;
char buffer[bufsz];
va_list args;
va_start (args, format);
vsnprintf (buffer, bufsz, format, args);
va_end (args);
buffer[bufsz - 1] = 0;
std::string value = "\"" + std::string(buffer) + "\"";
TraceNode* node = g_TraceLog->get_current_leaf();
node->add_attrib("str", key, value);
}
void trace_add_data(
const char* key,
float value
) {
if (std::isinf(value))
{
if (value > 0.0f)
{
value = std::numeric_limits<float>::max();
}
else
{
value = -std::numeric_limits<float>::max();
}
}
char buffer[256];
sprintf(buffer, "%.20g", (double)value);
TraceNode* node = g_TraceLog->get_current_leaf();
node->add_attrib("float", key, buffer);
}
void trace_add_data(
const char* key,
int value
) {
TraceNode* node = g_TraceLog->get_current_leaf();
node->add_attrib("int", key, std::to_string(value));
}
void trace_add_data(
const char* key,
unsigned int value
) {
TraceNode* node = g_TraceLog->get_current_leaf();
node->add_attrib("int", key, std::to_string(value));
}
#endif