diff --git a/CMakeLists.txt b/CMakeLists.txt index 27bc6a04fe..37dcd1ac0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,6 +239,7 @@ target_include_directories(embedded_softfloat PUBLIC ) include_directories("${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/include") set(SOFTFLOAT_LIBRARIES embedded_softfloat) +include_directories("${CMAKE_SOURCE_DIR}/deps/dbg-macro") find_package(Threads) diff --git a/deps/dbg-macro/LICENSE b/deps/dbg-macro/LICENSE new file mode 100644 index 0000000000..243854e613 --- /dev/null +++ b/deps/dbg-macro/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 David Peter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/deps/dbg-macro/README.md b/deps/dbg-macro/README.md new file mode 100644 index 0000000000..a142d31432 --- /dev/null +++ b/deps/dbg-macro/README.md @@ -0,0 +1,172 @@ +# `dbg(…)` + +[![Build Status](https://travis-ci.org/sharkdp/dbg-macro.svg?branch=master)](https://travis-ci.org/sharkdp/dbg-macro) [![Build status](https://ci.appveyor.com/api/projects/status/vmo9rw4te2wifkul/branch/master?svg=true)](https://ci.appveyor.com/project/sharkdp/dbg-macro) [![Try it online](https://img.shields.io/badge/try-online-f34b7d.svg)](https://repl.it/@sharkdp/dbg-macro-demo) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](dbg.h) + +*A macro for `printf`-style debugging fans.* + +Debuggers are great. But sometimes you just don't have the time or patience to set +up everything correctly and just want a quick way to inspect some values at runtime. + +This projects provides a [single header file](dbg.h) with a `dbg(…)` +macro that can be used in all circumstances where you would typically write +`printf("…", …)` or `std::cout << …`. But it comes with a few extras. + +## Examples + +``` c++ +#include +#include + +// You can use "dbg(..)" in expressions: +int factorial(int n) { + if (dbg(n <= 1)) { + return dbg(1); + } else { + return dbg(n * factorial(n - 1)); + } +} + +int main() { + std::string message = "hello"; + dbg(message); // [example.cpp:15 (main)] message = "hello" (std::string) + + const int a = 2; + const int b = dbg(3 * a) + 1; // [example.cpp:18 (main)] 3 * a = 6 (int) + + std::vector numbers{b, 13, 42}; + dbg(numbers); // [example.cpp:21 (main)] numbers = {7, 13, 42} (size: 3) (std::vector) + + dbg("this line is executed"); // [example.cpp:23 (main)] this line is executed + + factorial(4); + + return 0; +} +``` + +The code above produces this output ([try it yourself](https://repl.it/@sharkdp/dbg-macro-demo)): + +![dbg(…) macro output](https://i.imgur.com/NHEYk9A.png) + +## Features + + * Easy to read, colorized output (colors auto-disable when the output is not an interactive terminal) + * Prints file name, line number, function name and the original expression + * Adds type information for the printed-out value + * Specialized pretty-printers for containers, pointers, string literals, enums, `std::optional`, etc. + * Can be used inside expressions (passing through the original value) + * The `dbg.h` header issues a compiler warning when included (so you don't forget to remove it). + * Compatible and tested with C++11, C++14 and C++17. + +## Installation + +To make this practical, the `dbg.h` header should to be readily available from all kinds of different +places and in all kinds of environments. The quick & dirty way is to actually copy the header file +to `/usr/include` or to clone the repository and symlink `dbg.h` to `/usr/include/dbg.h`. +``` bash +git clone https://github.com/sharkdp/dbg-macro +sudo ln -s $(readlink -f dbg-macro/dbg.h) /usr/include/dbg.h +``` +If you don't want to make untracked changes to your filesystem, check below if there is a package for +your operating system or package manager. + +### On Arch Linux + +You can install [`dbg-macro` from the AUR](https://aur.archlinux.org/packages/dbg-macro/): +``` bash +yay -S dbg-macro +``` + +### With vcpkg + +You can install the [`dbg-macro` port](https://github.com/microsoft/vcpkg/tree/master/ports/dbg-macro) via: +``` bash +vcpkg install dbg-macro +``` + +## Configuration + +* Set the `DBG_MACRO_DISABLE` flag to disable the `dbg(…)` macro (i.e. to make it a no-op). +* Set the `DBG_MACRO_NO_WARNING` flag to disable the *"'dbg.h' header is included in your code base"* warnings. + +## Advanced features + +### Hexadecimal, octal and binary format + +If you want to format integers in hexadecimal, octal or binary representation, you can +simply wrap them in `dbg::hex(…)`, `dbg::oct(…)` or `dbg::bin(…)`: +```c++ +const uint32_t secret = 12648430; +dbg(dbg::hex(secret)); +``` + +### Printing type names + +`dbg(…)` already prints the type for each value in parenthesis (see screenshot above). But +sometimes you just want to print a type (maybe because you don't have a value for that type). +In this case, you can use the `dbg::type()` helper to pretty-print a given type `T`. +For example: +```c++ +template +void my_function_template() { + using MyDependentType = typename std::remove_reference::type&&; + dbg(dbg::type()); +} +``` + +### Print the current time + +To print a timestamp, you can use the `dbg::time()` helper: +```c++ +dbg(dbg::time()); +``` + +### Customization + +If you want `dbg(…)` to work for your custom datatype, you can simply overload `operator<<` for +`std::ostream&`: +```c++ +std::ostream& operator<<(std::ostream& out, const user_defined_type& v) { + out << "…"; + return out; +} +``` + +If you want to modify the type name that is printed by `dbg(…)`, you can add a custom +`get_type_name` overload: +```c++ +// Customization point for type information +namespace dbg { + std::string get_type_name(type_tag) { + return "truth value"; + } +} +``` + +## Development + +If you want to contribute to `dbg-macro`, here is how you can build the tests and demos: + +Make sure that the submodule(s) are up to date: +```bash +git submodule update --init +``` + +Then, use the typical `cmake` workflow. Usage of `-DCMAKE_CXX_STANDARD=17` is optional, +but recommended in order to have the largest set of features enabled: +```bash +mkdir build +cd build +cmake .. -DCMAKE_CXX_STANDARD=17 +make +``` + +To run the tests, simply call: +```bash +make test +``` +You can find the unit tests in `tests/basic.cpp`. + +## Acknowledgement + +This project is inspired by Rusts [`dbg!(…)` macro](https://doc.rust-lang.org/std/macro.dbg.html). diff --git a/deps/dbg-macro/dbg.h b/deps/dbg-macro/dbg.h new file mode 100644 index 0000000000..3a76130514 --- /dev/null +++ b/deps/dbg-macro/dbg.h @@ -0,0 +1,711 @@ +/***************************************************************************** + + dbg(...) macro + +License (MIT): + + Copyright (c) 2019 David Peter + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*****************************************************************************/ + +#ifndef DBG_MACRO_DBG_H +#define DBG_MACRO_DBG_H + +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#define DBG_MACRO_UNIX +#elif defined(_MSC_VER) +#define DBG_MACRO_WINDOWS +#endif + +#ifndef DBG_MACRO_NO_WARNING +#pragma message("WARNING: the 'dbg.h' header is included in your code base") +#endif // DBG_MACRO_NO_WARNING + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DBG_MACRO_UNIX +#include +#endif + +#if __cplusplus >= 201703L || defined(_MSC_VER) +#define DBG_MACRO_CXX_STANDARD 17 +#elif __cplusplus >= 201402L +#define DBG_MACRO_CXX_STANDARD 14 +#else +#define DBG_MACRO_CXX_STANDARD 11 +#endif + +#if DBG_MACRO_CXX_STANDARD >= 17 +#include +#include +#endif + +namespace dbg { + +#ifdef DBG_MACRO_UNIX +inline bool isColorizedOutputEnabled() { + return isatty(fileno(stderr)); +} +#else +inline bool isColorizedOutputEnabled() { + return true; +} +#endif + +struct time {}; + +namespace pretty_function { + +// Compiler-agnostic version of __PRETTY_FUNCTION__ and constants to +// extract the template argument in `type_name_impl` + +#if defined(__clang__) +#define DBG_MACRO_PRETTY_FUNCTION __PRETTY_FUNCTION__ +static constexpr size_t PREFIX_LENGTH = + sizeof("const char *dbg::type_name_impl() [T = ") - 1; +static constexpr size_t SUFFIX_LENGTH = sizeof("]") - 1; +#elif defined(__GNUC__) && !defined(__clang__) +#define DBG_MACRO_PRETTY_FUNCTION __PRETTY_FUNCTION__ +static constexpr size_t PREFIX_LENGTH = + sizeof("const char* dbg::type_name_impl() [with T = ") - 1; +static constexpr size_t SUFFIX_LENGTH = sizeof("]") - 1; +#elif defined(_MSC_VER) +#define DBG_MACRO_PRETTY_FUNCTION __FUNCSIG__ +static constexpr size_t PREFIX_LENGTH = + sizeof("const char *__cdecl dbg::type_name_impl<") - 1; +static constexpr size_t SUFFIX_LENGTH = sizeof(">(void)") - 1; +#else +#error "This compiler is currently not supported by dbg_macro." +#endif + +} // namespace pretty_function + +// Formatting helpers + +template +struct print_formatted { + static_assert(std::is_integral::value, + "Only integral types are supported."); + + print_formatted(T value, int numeric_base) + : inner(value), base(numeric_base) {} + + operator T() const { return inner; } + + const char* prefix() const { + switch (base) { + case 8: + return "0o"; + case 16: + return "0x"; + case 2: + return "0b"; + default: + return ""; + } + } + + T inner; + int base; +}; + +template +print_formatted hex(T value) { + return print_formatted{value, 16}; +} + +template +print_formatted oct(T value) { + return print_formatted{value, 8}; +} + +template +print_formatted bin(T value) { + return print_formatted{value, 2}; +} + +// Implementation of 'type_name()' + +template +const char* type_name_impl() { + return DBG_MACRO_PRETTY_FUNCTION; +} + +template +struct type_tag {}; + +template +std::string get_type_name(type_tag) { + namespace pf = pretty_function; + + std::string type = type_name_impl(); + return type.substr(pf::PREFIX_LENGTH, + type.size() - pf::PREFIX_LENGTH - pf::SUFFIX_LENGTH); +} + +template +std::string type_name() { + if (std::is_volatile::value) { + if (std::is_pointer::value) { + return type_name::type>() + " volatile"; + } else { + return "volatile " + type_name::type>(); + } + } + if (std::is_const::value) { + if (std::is_pointer::value) { + return type_name::type>() + " const"; + } else { + return "const " + type_name::type>(); + } + } + if (std::is_pointer::value) { + return type_name::type>() + "*"; + } + if (std::is_lvalue_reference::value) { + return type_name::type>() + "&"; + } + if (std::is_rvalue_reference::value) { + return type_name::type>() + "&&"; + } + return get_type_name(type_tag{}); +} + +inline std::string get_type_name(type_tag) { + return "short"; +} + +inline std::string get_type_name(type_tag) { + return "unsigned short"; +} + +inline std::string get_type_name(type_tag) { + return "long"; +} + +inline std::string get_type_name(type_tag) { + return "unsigned long"; +} + +inline std::string get_type_name(type_tag) { + return "std::string"; +} + +template +std::string get_type_name(type_tag>>) { + return "std::vector<" + type_name() + ">"; +} + +template +std::string get_type_name(type_tag>) { + return "std::pair<" + type_name() + ", " + type_name() + ">"; +} + +template +std::string type_list_to_string() { + std::string result; + auto unused = {(result += type_name() + ", ", 0)..., 0}; + static_cast(unused); + + if (sizeof...(T) > 0) { + result.pop_back(); + result.pop_back(); + } + return result; +} + +template +std::string get_type_name(type_tag>) { + return "std::tuple<" + type_list_to_string() + ">"; +} + +template +inline std::string get_type_name(type_tag>) { + return type_name(); +} + +// Implementation of 'is_detected' to specialize for container-like types + +namespace detail_detector { + +struct nonesuch { + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + void operator=(nonesuch const&) = delete; +}; + +template +using void_t = void; + +template + class Op, + class... Args> +struct detector { + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> { + using value_t = std::true_type; + using type = Op; +}; + +} // namespace detail_detector + +template