Commit 2ad458c2 authored by Ian Bell's avatar Ian Bell
Browse files

DEBUG. Added new Base project currently conmtaininging just DebOut.hh and...

DEBUG. Added new Base project currently conmtaininging just DebOut.hh and DebStream.cc implementing DEB_enter_func, DEB_out, DEB_warning, and DEB_error (together with _if varients) and replaced a large number (not all) of std::cerr and std::cout measage streaming with DEB_out, DEB+warning, or DEB_error as appropriate, All such text is currently piped to std::cerr in both Release and Debug builds, but this will probably be changed in a future CL.

[git-p4: depot-paths = "//ReForm/ReForm/main/Base/": change = 10440]
parent 7ceb55b8
cmake_minimum_required(VERSION 3.0)
project(Base)
my_add_subdir(Debug)
include_directories(${PROJECT_SOURCE_DIR}/..)
add_library(Base ${SOURCES} ${HEADERS})
# target_link_libraries(Base)
if (MSVC)
# generate dllexport macros on Windows Win64 (we do not support x32 platforms)
add_definitions(-D_SCL_SECURE_NO_DEPRECATE)
add_definitions(-D_USE_MATH_DEFINES)
add_definitions(-DNOMINMAX)
add_definitions(/W0) #add appropriate warnings flags for this project, the compilation raises too may warnings
add_definitions(/MP) #build on all cores
endif (MSVC)
set(my_headers
${CMAKE_CURRENT_SOURCE_DIR}/DebOut.hh
PARENT_SCOPE
)
set(my_sources
${CMAKE_CURRENT_SOURCE_DIR}/DebStream.cc
PARENT_SCOPE
)
// (C) Copyright 2014 by Autodesk, Inc.
//
// The information contained herein is confidential, proprietary
// to Autodesk, Inc., and considered a trade secret as defined
// in section 499C of the penal code of the State of California.
// Use of this information by anyone other than authorized
// employees of Autodesk, Inc. is granted only under a written
// non-disclosure agreement, expressly prescribing the scope
// and manner of such use.
#ifndef REFORM_DEBUG_OUT_HH_INCLUDED
#define REFORM_DEBUG_OUT_HH_INCLUDED
#define DEB_out_INCLUDED 1 // TODO: Define as a Cmake defined DEB_ON
#ifndef DEB_out_INCLUDED
#define DEB_enter_func
#define DEB_only( CC )
#define DEB_out(LL, AA )
#define DEB_out_if( CC, LL, AA )
#define DEB_warning( LL, AA )
#define DEB_warning_if( CC, LL, AA )
#define DEB_mesh_if( CC, LL, FF, MM )
#define DEB_error(AA)
#define DEB_error_if(CC, AA)
#else // DEB_out_INCLUDED
#include <string>
namespace ReForm {}
/* TODO: This should use an atomic thread safe static int
*/
#define DEB_enter_func static int deb_enter_count =0; \
ReForm::DebEnter deb(__FUNCTION__, deb_enter_count++);
#define DEB_only( CC ) CC
#define DEB_out(LL, AA ) { if (deb.permission(LL)) { deb.stream() << AA ; } }
#define DEB_out_if( CC, LL, AA ) { if (deb.permission(LL) && (CC)) { deb.stream() << AA ; } }
#define DEB_warning(LL, AA ) { if (deb.permission(LL, 1)) { deb.stream(1) << AA << "\n"; } }
#define DEB_warning_if( CC, LL, AA ) { if (deb.permission(LL, 1) && (CC)) \
{ deb.stream(1) << AA << "\n"; } }
#define DEB_mesh_out_if( CC, LL, FF, MM ) { if (deb.permission(LL, 2) && (CC)) \
{ deb.stream(2) << deb.mesh(FF, MM) ; } }
// TODO: implement Deb.mesh() filename and mesh holding class and assocated
// DebStream streamer
#define DEB_error(AA) DEB_out(0, "Error:" << AA << "\n")
#define DEB_error_if(CC, AA) if (CC) DEB_error(AA)
// DebStream does not fulfill ostream. If you want to exploit an existing
// ostream streamer to DEB_out a class as text without exploiting any
// numeric processing or custom DebStream streamers then use this macro thus
// DEB_out(1, "my_class is " << DEB_os_str(my_c) )
#define DEB_os_str(AA) dynamic_cast<std::ostringstream &>((std::ostringstream() << AA )).str()
namespace ReForm
{
class DebStream;
// Class used to maintain DebStream's CallStack
// This does not currently contain a pointer to the file streamer used
// but might do in future. It currently just contains an integer counter
// determining whether a given DEB_out should include or omit a call stack
// or a Deb destructor output some kind of closing function exit trace.
class DebEnter
{
public:
int deb_outs_; //!< Number of DEB_outs encountered within this function
DebEnter(const char * _funcname, int _count);
~DebEnter();
DebStream& stream(int _warn = 0, bool _print = true);
bool permission(int _lev, int _warn=0);
};
// C++ needs sight of this class definition to compile the below declared
// << streamers for some reason. Otherwise could move into DebStream.cc
#if 1
class DebStream
{
public:
enum StreamType
{
append = 0x01,
html = 0x02,
retain = 0x04,
keep_open = 0x08
};
private:
class Impl;
Impl * impl_;
Impl * impl() { return impl_;}
public:
//! Constructor.
DebStream(
const char * _file_name = nullptr, //!< [in] File name if file based.
const StreamType _type = append //!< [in] bitsfield enum type identifier
) ;
~DebStream();
DebStream& print(const int);
DebStream& print(const double);
DebStream& print(const char * const, bool fork = true);
DebStream& print(const char);
//! Output to file, if any.
int flush();
//! Add footer, flush, and close file.
void close();
//! Wipe all buffers, rendering future flush() inactive.
void clear();
//! Set debug level.
void set_level(int, int _warn=0);
//! Are we at the start of a text line?
bool at_line_start();
//! Get the currently active DebStream
static DebStream& get_global(int _warn=0);
static void set_global_name(const char * name, int _warn = 0);
void set_file_name(const char * _name);
bool permission(int _lev, int _warn=0);
void indent(int _depth);
//void add_to_call_stack(const char * _funcname, const int _count);
class CallStack;
class FunctionCallSequence;
CallStack& call_stack();
};
#endif
DebStream& operator<<(DebStream& ds, const int i );
DebStream& operator<<(DebStream& ds, const double d );
DebStream& operator<<(DebStream& ds, const size_t i );
DebStream& operator<<(DebStream& ds, const unsigned int i );
DebStream& operator<<(DebStream& ds, const float d );
DebStream& operator<<(DebStream& ds, const char c);
DebStream& operator<<(DebStream& ds, const char* const s );
DebStream& operator<<(DebStream& ds, const std::string& s );
// A std::stream streamer might be useful here. Add when needed.
}//namespace
#endif // DEB_out_INCLUDED
#endif // REFORM_DEBUG_OUT_HH_INCLUDED
// (C) Copyright 2014 by Autodesk, Inc.
//
// The information contained herein is confidential, proprietary
// to Autodesk, Inc., and considered a trade secret as defined
// in section 499C of the penal code of the State of California.
// Use of this information by anyone other than authorized
// employees of Autodesk, Inc. is granted only under a written
// non-disclosure agreement, expressly prescribing the scope
// and manner of such use.
#include "DebOut.hh"
#include <string>
#include <fstream>
#include <time.h>
#include <vector>
#include <iostream>
#ifdef DEB_out_INCLUDED
#define LOCAL_PROC static
LOCAL_PROC bool is_html_filename(const char * const str)
{
const char * dot = strchr(str, '.');
if (dot == nullptr) return false;
++dot;
return ( !strncmp(dot, "htm", 3) ) || ( !strncmp(dot,"HTM",3) ) ;
}
namespace ReForm
{
// This is currently in DebOut.hh instead
#if 0
class DebStream
{
public:
enum StreamType
{
append = 0x01,
html = 0x02,
retain = 0x04,
keep_open = 0x08
};
private:
class Impl;
Impl * impl_;
public:
//! Constructor.
DebStream(
const char * _file_name = nullptr, //!< [in] File name if file based.
const StreamType _type = append //!< [in] bitsfield enum type identifier
) ;
~DebStream();
DebStream& print(const int);
DebStream& print(const double);
DebStream& print(const char * const);
DebStream& print(const char);
//! Output to file, if any.
int flush();
//! Add footer, flush, and close file.
void close();
//! Wipe all buffers, rendering future flush() inactive.
void clear();
//! Set debug level.
void set_level(int, int _warn=0);
//! Are we at the start of a text line?
bool at_line_start();
//! Get the currently active DebStream
static DebStream& get_global(int _warn=0);
static void set_global_name(const char * name, int _warn = 0);
void set_file_name(const char * _name);
bool permission(int _lev, int _warn=0);
void indent(int _depth);
//void add_to_call_stack(const char * _funcname, const int _count);
class CallStack;
class FunctionCallSequence;
CallStack& call_stack();
private:
Impl * impl() { return impl_;}
};
#endif
// Can't easily put these in impl anymore
class DebStream::FunctionCallSequence
{
std::string func_name_;
std::vector<int> counts_; // These may not be sequential when multithreaded.
public:
DebStream::FunctionCallSequence(const char * _func_name, const int _count)
: func_name_(_func_name)
{
counts_.push_back(_count);
}
~FunctionCallSequence() {}
bool add(const char * _func_name, const int _count)
{
if (func_name_ == _func_name)
{
counts_.push_back(_count);
return true;
}
return false;
}
bool pop()
{
if (counts_.size() > 1 )
{
counts_.pop_back();
return true;
}
counts_.clear();
return false;
}
int number_calls() const
{
if (!this) return 0;
return (int)counts_.size();
}
int count(int i=0) const
{
int num = number_calls();
if (i < num) return counts_[num -1 - i];
return -1;
}
const char * name() const { return func_name_.c_str();}
// Replace interior of < > in function name with . for brevity
void compact_name(std::string & str) const
{
int cnt=0;
const char * ptr = func_name_.c_str();
while (ptr && (*ptr != '\0'))
{
char c = *ptr;
if (c=='>') --cnt;
if (cnt==0) str.append(1, c);
if (c=='<')
{
if (cnt==0) str.append(".");
++cnt;
}
++ptr;
}
}
// Get single call stack element string
void get(std::string& str, const bool _strip_angled, bool _with_counts) const
{
if (_strip_angled) compact_name(str);
else str.append(name());
str.append("[");
if (_with_counts)
{
int num = number_calls();
int prev = -2;
int seq_cnt =0;
for (int i=0; i < num; ++i)
{
int cnt = counts_[i];
if (cnt != prev + 1)
{
char buffer[64];
if (seq_cnt > 0)
{
str.append("-");
sprintf_s(buffer, sizeof(buffer), "%i", prev);
str.append(buffer);
}
if (i>0) str.append(",");
sprintf_s(buffer, sizeof(buffer), "%i", cnt);
str.append(buffer);
seq_cnt=0;
}
else
++seq_cnt;
prev = cnt;
} // endfor i
} // endif _with_counts
else
{
str.append("*");
}
str.append("]");
} // endfunc get
}; // endclass FunctionCallSequence
class DebStream::CallStack
{
std::vector<FunctionCallSequence> calls_;
int depth_;
public:
CallStack() : depth_(0) {}
~CallStack() {}
void add(const char * _func_name, const int _count)
{
if (calls_.empty() || !calls_.back().add(_func_name, _count))
{
calls_.push_back( FunctionCallSequence(_func_name, _count) );
}
++depth_;
}
void pop()
{
if (!calls_.back().pop())
calls_.pop_back();
--depth_;
}
const FunctionCallSequence * call( int _up =0)
{
int num = (int)calls_.size();
if (_up < num) return &calls_[num - 1 - _up];
return nullptr;
}
// Read a particular call stack element
bool read(int _up, const char*& _funcname, int & _count)
{
const FunctionCallSequence * fcs = call(_up);
if (fcs != nullptr)
{
_funcname = fcs->name();
_count = fcs->count(0); // Return most recent deb_enter_count
return true;
}
return false;
}
// Get a full call stack sting.
// returns number of call stack function elements
int get(std::string& _str, bool _with_counts = true) const
{
int num = (int)calls_.size();
for (int i =0; i< num; ++i)
{
if (i>0) _str.append("->");
calls_[i].get(_str, true, _with_counts);
}
return num;
}
int depth() const { return depth_; }
}; // endclass CallStack
class DebStream::Impl
{
private:
StreamType type_;
int lev_;
int num_flush_;
std::string current_;
std::string output_;
std::string file_name_;
std::fstream file_stream_;
std::string indent_string_;
DebStream * deb_stream_;
CallStack call_stack_;
public:
CallStack& call_stack() { return call_stack_;}
bool is_kept_open() const { return type_ & StreamType::keep_open; }
bool is_html() const { return type_ & StreamType::html; }
bool is_retained() const { return type_ & StreamType::retain; }
bool is_appended() const { return type_ & StreamType::append; }
// Only applies to HTML DEB_out
bool is_white_on_black() { return true; }
bool file_is_open() const { return file_stream_.is_open(); }
bool fork_to_cout() { return false; }
bool fork_to_cerr() { return true; }
const char * file_name() const
{
if ( this && (!file_name_.empty()) ) return file_name_.c_str();
return nullptr;
}
void clear()
{
current_.clear();
output_.clear();
file_name_.clear();
}
Impl(
DebStream* _deb_stream,
StreamType _type = (StreamType) (append | retain),
const char * _file_name = nullptr) :
type_(_type), lev_(9), deb_stream_(_deb_stream), num_flush_(0)
{
set_file_name(_file_name);
indent_string_ = ".";
}
~Impl() {}
char prev_char() const
{
if (!current_.empty()) return current_.back();
if (!output_.empty()) return output_.back();
return '\0';
}
void line_break(bool _with_indent=false)
{
_with_indent;
if ( is_html() ) current_.append("<br>"); // Don't bother with matching </br>
current_.append("\n", 1);
// Don't add indent yet because we might not want it.
}
void indent(int _depth)
{
if (!indent_string_.empty())
{
for (int i=0; i < _depth; ++i) current_.append(indent_string_);
}
}
void set_level(int _lev) { lev_ = _lev; }
void print(const char _c)
{
if (_c == '\n') line_break();
else current_.append(&_c, 1);
}
void print(const char * const _s, bool _fork = true)
{
if (_s != nullptr)
{
for (int i=0; ;++i)
{
const char c = _s[i];
if(c=='\0') break;
print(c);
}
if (_fork)
{
if (fork_to_cout()) std::cout << _s;
if (fork_to_cerr()) std::cerr << _s;
}
}
}
void print(int _i)
{
char buffer[64];
sprintf_s(buffer, sizeof(buffer), "%i", _i);
print(buffer);
}
void print(double _d)
{
char buffer[64];
sprintf_s(buffer, sizeof(buffer), "%.17g", _d);
print(buffer);
}
DebStream & stream() { return *deb_stream_; }
void header(std::string & str)
{
if ( is_html() )
{
str.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\">");
str.append("\n<HTML><HEAD>");
str.append("\n<TITLE>ReForm DEB_out");
str.append("</TITLE>");
// javascript lib loads go here
// stylesheet loads go here
// within HEAD javascript goes here
str.append("\n</HEAD>");
if( is_white_on_black() )
{
str.append( "\n<BODY BGCOLOR=\"#000000\" TEXT=\"#FFFFFF\" LINK=\"#%00FFFF\" VLINK=\"#FFFF00\" >");
}
else
{
str.append("\n<BODY BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\" LINK=\"#%FF0000\" VLINK=\"#0000FF\" >");
}
str.append("\n");
} // endif is_html
bool date_header = true;
if (date_header)
{
time_t rawtime;
struct tm * timeinfo;
time ( &