All Projects β†’ renatoGarcia β†’ Icecream Cpp

renatoGarcia / Icecream Cpp

Licence: other
🍦 Never use cout/printf to debug again

Programming Languages

cpp
1120 projects
cpp11
221 projects
cpp17
186 projects
cpp14
131 projects

Projects that are alternatives of or similar to Icecream Cpp

Icecream
🍦 Never use print() to debug again.
Stars: ✭ 5,601 (+2389.33%)
Mutual labels:  debugging, debug, debugging-tool, print
pydbg
Python implementation of the Rust `dbg` macro
Stars: ✭ 85 (-62.22%)
Mutual labels:  debugging, debug, print, debugging-tool
Bugsnag Ruby
Bugsnag error monitoring & reporting software for rails, sinatra, rack and ruby
Stars: ✭ 211 (-6.22%)
Mutual labels:  debugging, debug, debugging-tool
Debugo
δΈ€δΈͺε―θƒ½ζœ‰η‚Ήη”¨ηš„ iOS θ°ƒθ―•ε·₯ε…·~
Stars: ✭ 258 (+14.67%)
Mutual labels:  debugging, debug, debugging-tool
Tensorwatch
Debugging, monitoring and visualization for Python Machine Learning and Data Science
Stars: ✭ 3,191 (+1318.22%)
Mutual labels:  debugging, debug, debugging-tool
ducky
Chrome extension to overlay a (super adorable) rubber duck, as a virtual companion during rubber duck debugging.
Stars: ✭ 80 (-64.44%)
Mutual labels:  debugging, debug, debugging-tool
docker-pudb
Debug Python code within a Docker container remotely from your terminal using pudb
Stars: ✭ 18 (-92%)
Mutual labels:  debugging, debug, debugging-tool
caddy-trace
Request Debugging Middleware Plugin for Caddy v2
Stars: ✭ 25 (-88.89%)
Mutual labels:  debugging, debug, debugging-tool
Xcglogger
A debug log framework for use in Swift projects. Allows you to log details to the console (and optionally a file), just like you would have with NSLog() or print(), but with additional information, such as the date, function name, filename and line number.
Stars: ✭ 3,710 (+1548.89%)
Mutual labels:  debugging, debug, debugging-tool
Bugsnag Laravel
Bugsnag notifier for the Laravel PHP framework. Monitor and report Laravel errors.
Stars: ✭ 746 (+231.56%)
Mutual labels:  debugging, debug, debugging-tool
Bugsnag Android
Bugsnag crash monitoring and reporting tool for Android apps
Stars: ✭ 990 (+340%)
Mutual labels:  debugging, debug, debugging-tool
dwarf import
This loads DWARF info from an open binary and propagates function names, arguments, and type info
Stars: ✭ 18 (-92%)
Mutual labels:  debugging, debug, debugging-tool
bugsnag-vue
[DEPRECATED] This package now lives within the monorepo for our Universal JS notifier "@bugsnag/js" β€’ https://github.com/bugsnag/bugsnag-js
Stars: ✭ 26 (-88.44%)
Mutual labels:  debugging, debug, debugging-tool
Gdb Frontend
β˜• GDBFrontend is an easy, flexible and extensionable gui debugger.
Stars: ✭ 2,104 (+835.11%)
Mutual labels:  debugging, debug, debugging-tool
bugsnag-java
Bugsnag error reporting for Java.
Stars: ✭ 51 (-77.33%)
Mutual labels:  debugging, debug, debugging-tool
Cocoadebug
iOS Debugging Tool πŸš€
Stars: ✭ 3,769 (+1575.11%)
Mutual labels:  debugging, debug, debugging-tool
Bugsnag Node
[DEPRECATED] Please upgrade to our Universal JS notifier "@bugsnag/js" β€’ https://github.com/bugsnag/bugsnag-js
Stars: ✭ 48 (-78.67%)
Mutual labels:  debugging, debug, debugging-tool
Godbg
Go implementation of the Rust `dbg` macro
Stars: ✭ 172 (-23.56%)
Mutual labels:  debugging, debug, print
Scala Trace Debug
Macro based print debugging. Locates log statements in your IDE.
Stars: ✭ 110 (-51.11%)
Mutual labels:  debugging, debug
Pandora
an android library for debugging what we care about directly in app.
Stars: ✭ 1,365 (+506.67%)
Mutual labels:  debug, debugging-tool

IceCream-Cpp

CI.badge LICENSE.badge

IceCream-Cpp is a little (single header) library to help with the print debugging on C++11 and forward.

Try it at godbolt!

Contents

With IceCream-Cpp, an execution inspection:

auto my_function(int i, double d) -> void
{
    std::cout << "1" << std::endl;
    if (condition)
        std::cout << "2" << std::endl;
    else
        std::cout << "3" << std::endl;
}

can be coded instead:

auto my_function(int i, double d) -> void
{
    IC();
    if (condition)
        IC();
    else
        IC();
}

and will print something like:

ic| test.cpp:34 in "void my_function(int, double)"
ic| test.cpp:36 in "void my_function(int, double)"

Also, any variable inspection like:

std::cout << "a: " << a
          << ", b: " << b
          << ", sum(a, b): " << sum(a, b)
          << std::endl;

can be simplified to:

IC(a, b, (sum(a, b)));

and will print:

ic| a: 7, b: 2, (sum(a, b)): 9

This library is inspired by and aims to behave the most identical as possible to the original Python IceCream library.

Install

The IceCream-Cpp is a one file, header only library, having the STL as its only dependency. The most direct way to install it is just copy the icecream.hpp header to inside your project.

To properly install it system wide, together with the CMake project files, run on IceCream-Cpp project root directory:

mkdir build
cd build
cmake ..
cmake --install .

Nix

If using Nix, any committed version on master branch can be installed using the archive https://github.com/renatoGarcia/icecream-cpp/archive/<commmit>.tar.gz, where <commit>.tar.gz could be any tag or commit hash of master branch.

For instance, to install the master HEAD commit, environment wide:

nix-env -if https://github.com/renatoGarcia/icecream-cpp/archive/master.tar.gz

To use a specific commit in a shell.nix:

icecream-cpp = pkgs.callPackage (
  fetchTarball https://github.com/renatoGarcia/icecream-cpp/archive/<commit>.tar.gz
) { inherit pkgs; };

where pkgs is the variable with the evaluated nixpkgs.

Conan

The released versions are available on Conan too:

conan install icecream-cpp/[email protected]

Usage

If using CMake:

find_package(IcecreamCpp)
include_directories(${IcecreamCpp_INCLUDE_DIRS})

will add the installed directory on include paths list.

After including the icecream.hpp header on a source file, here named test.cpp:

#include <icecream.hpp>

A macro IC(...) will be defined. If called with no arguments it will print the prefix (default ic|), the source file name, the current line number, and the current function signature. The code:

auto my_function(int foo, double bar) -> void
{
    // ...
    IC();
    // ...
}

will print:

ic| test.cpp:34 in "void my_function(int, double)"

If called with arguments it will print the prefix, those arguments names, and its values. The code:

auto v0 = std::vector<int> {1, 2, 3};
auto s0 = std::string {"bla"};
IC(v0, s0, 3.14);

will print:

ic| v0: [1, 2, 3], s0: "bla", 3.14: 3.14

Return value

If called with no arguments the IC(...) macro will return void, if called with one argument it will return the argument itself, and if called with multiple arguments it will return a tuple with all of them:

auto a = int {7};
auto b = std::string {"bla"};
auto c = float {3.14};

IC();
int& d = IC(a);
std::tuple<std::string&, float&> e = IC(b, c);

Configuration

The Icecream class is internally implemented as a singleton. All the configuration changes will be done to a unique object, and shared across all the program and threads.

All configurations are done/viewed through accessor methods, using the icecream::ic object. To allow the method chaining idiom all the set methods return a reference of the ic object:

icecream::ic
    .prefix("ic: ")
    .show_c_string(false)
    .line_wrap_width(70);

For simplification purposes, on the following examples a using icecream::ic statement will be presumed.

enable/disable

Enable or disable the output of IC(...) macro, enabled default.

  • set:
    auto enable() -> IcecreamAPI&;
    auto disable() -> IcecreamAPI&;
    

The code:

IC(1);
ic.disable();
IC(2);
ic.enable();
IC(3);

will print:

ic| 1: 1
ic| 3: 3

stream

Warning: this method will return a reference to the internal std::ostream. The operations done on that reference will not be thread safe.

The std::ostream where the output will be streamed.

  • get:
    auto stream() -> std::ostream&;
    

The default stream buffer associated is the same as std::cerr, but that can be changed. For instance, to stream the output to a string:

auto sstr = std::stringstream {};
ic.stream().rdbuf(sstr.rdbuf());

prefix

The text that will be printed before each output. It can be set to a string, a nullary callable that returns an object having an overload of operator<<(ostream&, T), or any number of instances of those two. The printed prefix will be a concatenation of all those elements.

  • set:
    template <typename... Ts>
    auto prefix(Ts&& ...values) -> IcecreamAPI&;
    

The code:

ic.prefix("icecream| ");
IC(1);
ic.prefix([]{return 42;}, "- ");
IC(2);
ic.prefix("thread ", std::this_thread::get_id, " | ");
IC(3);

will print:

icecream| 1: 1
42- 2: 2
thread 1 | 3: 3

show_c_string

Controls if a char* variable should be interpreted as a null-terminated C string (true) or a pointer to a char (false). The default value is true.

  • get:
    auto show_c_string() const -> bool;
    
  • set:
    auto show_c_string(bool value) -> IcecreamAPI&;
    

The code:

char const* flavor = "mango";

ic.show_c_string(true);
IC(flavor);

ic.show_c_string(false);
IC(flavor);

will print:

ic| flavor: "mango";
ic| flavor: 0x55587b6f5410

line_wrap_width

The maximum number of characters before the output be broken on multiple lines. Default value of 70.

  • get:
    auto line_wrap_width() const -> std::size_t;
    
  • set:
    auto line_wrap_width(std::size_t value) -> IcecreamAPI&;
    

include_context

If the context (source name, line number, and function name) should be printed even when printing variables. Default value is false.

  • get:
    auto include_context() const -> bool;
    
  • set:
    auto include_context(bool value) -> IcecreamAPI&;
    

context_delimiter

The string separating the context text from the variables values. Default value is "- ".

  • get:
    auto context_delimiter() const -> std::string;
    
  • set:
    auto context_delimiter(std::string const& value) -> IcecreamAPI&;
    

Printing logic

When printing a type T, the precedence is use an overloaded function operator<<(ostream&, T) always when it is available. The exceptions to that rule are strings (C strings, std::string, and std::string_view), char and bounded arrays. Strings will be enclosed by ", char will be enclosed by ', and arrays are considered iterables rather than let decay to raw pointers.

In general, if an overload of operator<<(ostream&, T) is not available to a type T, a call to IC(t) will result on a compiling error. All exceptions to that rule, when IceCream-Cpp will print a type T even without a operator<< overload are discussed below. Note however that even to those, if a user implements a custom operator<<(ostream&, T) that will take precedence and used instead.

C strings

C strings are ambiguous. Should a char* foo variable be interpreted as a pointer to a single char or as a null-terminated string? Likewise, is the char bar[] variable an array of single characters or a null-terminated string? Is char baz[3] an array with three single characters or is it a string of size two plus a '\0'?

Each one of those interpretations of foo, bar, and baz would be printed in a distinct way. To the code:

char flavor[] = "pistachio";
IC(flavor);

all three outputs below are correct, each one having a distinct interpretation of what should be the flavor variable.

ic| flavor: 0x55587b6f5410
ic| flavor: ['p', 'i', 's', 't', 'a', 'c', 'h', 'i', 'o', '\0']
ic| flavor: "pistachio"

The IceCream-Cpp policy is handle any bounded char array (i.e.: array with a known size) as an array of single characters. So the code:

char flavor[] = "chocolate";
IC(flavor);

will print:

ic| flavor: ['c', 'h', 'o', 'c', 'o', 'l', 'a', 't', 'e', '\0']

unbounded char[] arrays (i.e.: array with an unknown size) will decay to char* pointers, and will be printed either as a string or a pointer as configured by the show_c_string option.

Pointer like types

The std::unique_ptr<T> (before C++20) and boost::scoped_ptr<T> types will be printed like usual raw pointers.

The std::weak_ptr<T> and boost::weak_ptr<T> types will print their address if they are valid or "expired" otherwise. The code:

auto v0 = std::make_shared<int>(7);
auto v1 = std::weak_ptr<int> {v0};

IC(v1);
v0.reset();
IC(v1);

will print:

ic| v1: 0x55bcbd840ec0
ic| v1: expired

Iterable types

If for a type A with an instance a, all following operations are valid:

auto it = begin(a);
it != end(a);
++it;
*it;

the type A is defined iterable, and if A has no overload of operator<<(ostream&, A), all of its items will be printed instead. The code:

auto v0 = std::list<int> {10, 20, 30};
IC(v0);

will print:

ic| v0: [10, 20, 30]

Tuple like types

A std::pair<T1, T2> or std::tuple<Ts...> typed variables will print all of its elements.

The code:

auto v0 = std::make_pair(10, 3.14);
auto v1 = std::make_tuple(7, 6.28, "bla");
IC(v0, v1);

will print:

ic| v0: (10, 3.14), v1: (7, 6.28, "bla")

Optional types

A std::optional<T> typed variable will print its value, if it has one, or nullopt otherwise.

The code:

auto v0 = std::optional<int> {10};
auto v1 = std::optional<int> {};
IC(v0, v1);

will print:

ic| v0: 10, v1: nullopt

Variant types

A std::variant<Ts...> or boost::variant2::variant<Ts...> typed variable will print its value.

The code:

auto v0 = std::variant<int, double, char> {4.2};
IC(v0);

will print:

ic| v0: 4.2

Exception types

Types inheriting from std::exception will print the return of std::exception::what() method. If beyond that it inherits from boost::exception too, the response of boost::diagnostic_information() will be also printed.

The code:

auto v0 = std::runtime_error("error description");
IC(v0);

will print:

ic| v0: error description

Standard layout types (Clang only)

With some exceptions (see issue #7), if using Clang >= 7, any standard layout type (C compatible structs roughly speaking) is printable even without an operator<<(ostream&, T) overload.

The code:

class S
{
public:
    float f;
    int ii[3];
};

S s = {3.14, {1,2,3}};
IC(s);

will print:

ic| s: {f: 3.14, ii: [1, 2, 3]}

Pitfalls

The IC(...) is a preprocessor macro, then care must be taken when using arguments with commas. Any argument having commas must be enclosed by parenthesis. The code:

auto sum(int i0, int i1) -> int
{
    return i0 + i1;
}

// ...

IC((sum(40, 2)));

will work and print something like:

ic| (sum(40, 2)): 42

Also, since IC(...) is a preprocessor macro, it can cause conflicts if there is some other IC identifier on code. To change the IC(...) macro to a longer ICECREAM(...) one, just define ICECREAM_LONG_NAME before the inclusion of icecream.hpp header:

#define ICECREAM_LONG_NAME
#include "icecream.hpp"

While most compilers will work just fine, until the C++20 the standard requires at least one argument when calling a variadic macro. To handle this the nullary macros IC0() and ICECREAM0() are defined alongside IC(...) and ICECREAM(...).

Similar projects

The CleanType library has a focus on printing readable types names, but there is support to print variables names and values alongside its types.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].