Skip to content

Commit

Permalink
Utility: source location in Debug.
Browse files Browse the repository at this point in the history
  • Loading branch information
mosra committed Jun 27, 2019
1 parent 372c9df commit e4c1361
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 1 deletion.
3 changes: 3 additions & 0 deletions doc/corrade-changelog.dox
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ namespace Corrade {
- @ref Utility::Debug::packed and @ref Utility::Debug::color output modifiers
for tighter printing of container types and printing color-like values as
actual 24bit ANSI color sequences
- Ability to optionally prefix @ref Utility::Debug output with a source file
and line on supported compilers. See @ref Utility-Debug-source-location for
more information.
- New @ref Utility::Directory::append() and
@ref Utility::Directory::appendString() counterparts to
@ref Utility::Directory::write()
Expand Down
13 changes: 13 additions & 0 deletions doc/snippets/Utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,19 @@ Utility::Debug{} << "this has default color again";
/* [Debug-modifiers-colors-scoped] */
}

{
/* [Debug-source-location] */
float a = 336;

!Utility::Debug{} << "the result is" << (a /= 8);
!Utility::Debug{} << "but here it's" << (a /= 8);

!Utility::Debug{};

Utility::Debug{} << "and finally, " << (a *= 8);
/* [Debug-source-location] */
}

{
/* [Debug-nospace] */
Utility::Debug{} << "Value:" << 16 << Utility::Debug::nospace << "," << 24;
Expand Down
10 changes: 10 additions & 0 deletions src/Corrade/Corrade.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,16 @@ building Corrade.
*/
#define CORRADE_UTILITY_USE_ANSI_COLORS
#undef CORRADE_UTILITY_USE_ANSI_COLORS

/**
@brief Source location support in debug output
Defined if @ref Corrade::Utility::Debug "Utility::Debug" is able to print
source location support. Available only on GCC 8.1 and newer. See
@ref Utility-Debug-source-location for more information.
*/
#define CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION
#undef CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION
#endif

}
Expand Down
32 changes: 32 additions & 0 deletions src/Corrade/Utility/Debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@
#include "Corrade/Containers/EnumSet.hpp"
#include "Corrade/Utility/DebugStl.h"

#ifdef CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION
#include "Corrade/Utility/Assert.h"
#endif

namespace Corrade { namespace Utility {

namespace {
Expand Down Expand Up @@ -299,6 +303,15 @@ Debug::Debug(std::ostream* const output, const Flags flags): _flags{InternalFlag
#endif
}

#if !defined(DOXYGEN_GENERATING_OUTPUT) && defined(CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION)
namespace Implementation {
DebugSourceLocation::DebugSourceLocation(Debug&& debug, const std::experimental::source_location& location): debug{&debug} {
debug._sourceLocationFile = location.file_name();
debug._sourceLocationLine = location.line();
}
}
#endif

Warning::Warning(std::ostream* const output, const Flags flags): Debug{flags} {
/* Save previous global output and replace it with current one */
_previousGlobalWarningOutput = globalWarningOutput;
Expand All @@ -316,6 +329,16 @@ Warning::Warning(const Flags flags): Warning{globalWarningOutput, flags} {}
Error::Error(const Flags flags): Error{globalErrorOutput, flags} {}

void Debug::cleanupOnDestruction() {
#ifdef CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION
/* Print source location if not printed yet -- this means saying a
!Debug{}; will print just that, while Debug{}; is a no-op */
if(_output && _sourceLocationFile) {
CORRADE_INTERNAL_ASSERT(_immediateFlags & InternalFlag::NoSpace);
*_output << _sourceLocationFile << ":" << _sourceLocationLine;
_flags |= InternalFlag::ValueWritten;
}
#endif

/* Reset output color */
resetColorInternal();

Expand Down Expand Up @@ -355,6 +378,15 @@ Fatal::~Fatal() {
template<class T> Debug& Debug::print(const T& value) {
if(!_output) return *this;

#ifdef CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION
/* Print source location, if not printed yet */
if(_sourceLocationFile) {
CORRADE_INTERNAL_ASSERT(_immediateFlags & InternalFlag::NoSpace);
*_output << _sourceLocationFile << ":" << _sourceLocationLine << ": ";
_sourceLocationFile = nullptr;
}
#endif

/* Separate values with spaces if enabled; reset all internal flags after */
if(!((_immediateFlags|_flags) & InternalFlag::NoSpace))
*_output << ' ';
Expand Down
72 changes: 72 additions & 0 deletions src/Corrade/Utility/Debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,23 @@
#include "Corrade/Utility/Utility.h"
#include "Corrade/Utility/visibility.h"

#ifdef CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION
#if CORRADE_CXX_STANDARD < 201401
/* This feature could work even under C++11 if it didn't use constexpr */
#define constexpr /** @todo UGH what?! (submit a PR with this?) */
#endif
#include <experimental/source_location>
#if CORRADE_CXX_STANDARD < 201401
#undef constexpr
#endif
#endif

namespace Corrade { namespace Utility {

#ifdef CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION
namespace Implementation { struct DebugSourceLocation; }
#endif

/**
@brief Debug output handler
Expand Down Expand Up @@ -130,6 +145,31 @@ documentation for more information.
@include UtilityDebug-color-greyscale.ansi
@section Utility-Debug-source-location Source location
Similarly to the [dbg! macro in Rust](https://blog.rust-lang.org/2019/01/17/Rust-1.32.0.html#the-dbg-macro),
on supported compilers the utility is able to print source file location and
line where the debug output was executed, improving the "printf debugging"
experience. By default no source location info is printed, in order to do that
prefix the @ref Debug instantiation with an exclamation mark. Additionally,
an otherwise unused exclamated instantiation prints just the file + line alone
(in contrast to unexclamated instantiaton, which is a no-op):
@snippet Utility.cpp Debug-source-location
The above code then may print something like this:
@code{.shell-session}
main.cpp:10: the result is 42
main.cpp:11: the result is 5.25
main.cpp:13
and finally, 42
@endcode
At the moment, this feature is available only on GCC 8.1 and newer, elsewhere
it behaves like the unexclamated version. You can check for its availability
using the @ref CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION predefined macro.
@section Utility-Debug-multithreading Thread safety
If Corrade is compiled with @ref CORRADE_BUILD_MULTITHREADED enabled (the
Expand Down Expand Up @@ -603,6 +643,10 @@ class CORRADE_UTILITY_EXPORT Debug {
InternalFlags _immediateFlags;

private:
#ifdef CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION
friend Implementation::DebugSourceLocation;
#endif

template<Color c, bool bold> CORRADE_UTILITY_LOCAL static Modifier colorInternal();

CORRADE_UTILITY_LOCAL void resetColorInternal();
Expand All @@ -614,6 +658,10 @@ class CORRADE_UTILITY_EXPORT Debug {
Color _previousColor;
bool _previousColorBold;
#endif
#ifdef CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION
const char* _sourceLocationFile{};
int _sourceLocationLine{};
#endif
};

/** @debugoperatorclassenum{Debug,Debug::Color} */
Expand All @@ -628,6 +676,30 @@ CORRADE_UTILITY_EXPORT Debug& operator<<(Debug& debug, Debug::Flags value);
CORRADE_ENUMSET_OPERATORS(Debug::Flags)
CORRADE_ENUMSET_OPERATORS(Debug::InternalFlags)

#ifdef CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION
namespace Implementation {
struct CORRADE_UTILITY_EXPORT DebugSourceLocation {
/*implicit*/ DebugSourceLocation(Debug&& a, const std::experimental::source_location& location = std::experimental::source_location::current());
Debug* debug;
};
}

/* Unfortunately it's not possible to add additional (default) arguments to
operator! so we need to use a implicitly convertible type and capture the
source location in its constructor */
inline Debug& operator!(Implementation::DebugSourceLocation debug) {
return *debug.debug;
}
#else
/** @relatesalso Debug
@brief Prefix the output with source location
Only on supported compilers, does nothing otherwise. See
@ref Utility-Debug-source-location for more information.
*/
inline Debug& operator!(Debug&& debug) { return debug; }
#endif

#ifndef DOXYGEN_GENERATING_OUTPUT
/* so Debug() << value works */
template<class T> inline Debug& operator<<(Debug&& debug, const T& value) {
Expand Down
35 changes: 34 additions & 1 deletion src/Corrade/Utility/Test/DebugTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ struct DebugTest: TestSuite::Tester {
#ifndef CORRADE_TARGET_EMSCRIPTEN
void multithreaded();
#endif

void sourceLocation();
};

DebugTest::DebugTest() {
Expand Down Expand Up @@ -154,7 +156,8 @@ DebugTest::DebugTest() {
#ifndef CORRADE_TARGET_EMSCRIPTEN
&DebugTest::multithreaded,
#endif
});

&DebugTest::sourceLocation});
}

void DebugTest::debug() {
Expand Down Expand Up @@ -917,6 +920,36 @@ void DebugTest::multithreaded() {
}
#endif

void DebugTest::sourceLocation() {
std::ostringstream out;

{
Debug redirect{&out};

!Debug{} << "hello";

!Debug{} << "and this is from another line";

!Debug{};

Debug{} << "this no longer";
}

#ifdef CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION
CORRADE_COMPARE(out.str(),
__FILE__ ":929: hello\n"
__FILE__ ":931: and this is from another line\n"
__FILE__ ":933\n"
"this no longer\n");
#else
CORRADE_COMPARE(out.str(),
"hello\n"
"and this is from another line\n"
"this no longer\n");
CORRADE_SKIP("std::experimental::source_location not available.");
#endif
}

}}}}

CORRADE_TEST_MAIN(Corrade::Utility::Test::DebugTest)
5 changes: 5 additions & 0 deletions src/Corrade/configure.h.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,9 @@
/* Otherwise no idea. */
#endif

/* Source location support in Debug */
#if defined(__GNUC__) && __GNUC__*100 + __GNUC_MINOR__ >= 801
#define CORRADE_UTILITY_DEBUG_HAS_SOURCE_LOCATION
#endif

#endif

0 comments on commit e4c1361

Please sign in to comment.