sharkdp/dbg-macro

Print integral types as bit sizes instead of standard types

mhammerc opened this issue · 11 comments

Hello !

Another idea for improvements:

image

As for now, integral types are shown as int, unsigned int, etc

An idea is to print them as uint8, int8, uint16, etc

This is because an int does represent the size of the integral only for the platform it currently run.

I think a lot of developers do not use standard types (int, char, ...) but typedefs types (uint32_t, uint8_t, ...) just like me!

I think this is just a matter of updating theses lines with proper types even if there could be a better more generic way:
image

If you agree to this feature and you are not available, it will be my pleasure to provide a PR!

Thank you for the feedback.

I might not have considered every aspect of it, but it sounds like a good idea to me!
I personally also prefer uint64_t over unsigned long, etc.

Implementation-wise, I would suggest we introduce a helper macro:

#define DBG_MACRO_REGISTER_TYPE_NAME(type) \
  inline std::string get_type_name(type_tag<type>) { return #type; }

DBG_MACRO_REGISTER_TYPE_NAME(uint8_t);
DBG_MACRO_REGISTER_TYPE_NAME(uint16_t);
DBG_MACRO_REGISTER_TYPE_NAME(uint32_t);
DBG_MACRO_REGISTER_TYPE_NAME(uint64_t);
DBG_MACRO_REGISTER_TYPE_NAME(int8_t);
DBG_MACRO_REGISTER_TYPE_NAME(int16_t);
DBG_MACRO_REGISTER_TYPE_NAME(int32_t);
DBG_MACRO_REGISTER_TYPE_NAME(int64_t);
DBG_MACRO_REGISTER_TYPE_NAME(std::string);

A few tests need to be adapted, but I'm fine with replacing int => int32_t, unsigned short => uint16_t, etc.

The README also needs to be adapted.

This sounds like a good place to put in a new config option. Put an ifdef here to allow switching between using bits and standard types.
Ensures everyone is happy.

@sharkdp Good idea!

@DerekCresswell It's a good idea as it would not require any additional engineering!

I would try to avoid adding additional configuration flags. dbg.h is designed to work "out of the box". Adding another compile-time switch also increases the complexity of the code and the tests.

Instead, we could simply show both. Let's say a user prints an int and int ~ int32_t on his platform. We would then show something like

[tests.cpp:76 (main)] x = 42 (int ~ int32_t)

If !std::is_same<int, int32_t>::value on this platform, we would only show int.

I think there is no need to have a mandatory int == int32_t.

We could not print _t suffix, to keep only the essential part: [u]int<size * 8>

It is easy to write in plain C++ but require some additional code to write and maintain. It should also be possible to write it as constexpr, so each template specialization result is stored in binary and compute is made at compile-time.

    template <typename Type>
    get_type()
    {
        std::string type_string {}; // or something without dynamic memory management
        type_string.reserve(7); // max type size: uint128 -> 7 chars
        // std::is_unsigned or something like this
        // sizeof(Type) * 8
    }

I think there is no need to have a mandatory int == int32_t.

you mean... even if sizeof(int) == 4, we could have std::is_same<int, int32_t>::value evaluate to false?

No, sorry. I meant that we can compute int32 at run-time or compile-time instead of forcing associations like int = int32_t !

I wouldn't force this association. I would test for it. Something like:

inline std::string get_type_name(type_tag<int>) {
  return std::is_same<int, int32_t>::value ? "int ~ int32_t" : "int";
}

And yes, this function could be constexpr if we can generally return a const char* instead of a string.

inline std::string get_type_name(type_tag<int>) {
  return std::is_same<int, int32_t>::value ? "int ~ int32_t" : "int";
}

I feel like with this implementation output for other class templates will be messy. For ex, outputs like these

[main.cc:21 (solve)] v = {} (std::vector<std::pair<int ~ int32_t, int ~ int32_t>>)

We could rather prefer bit size variant over the standard types when std::is_same_v<int, int32_t> evaluates to true and register all such associations using a macro as you suggested here. Something like

#define DBG_MACRO_REGISTER_TYPE_ASSOC(t_std, t_bit) \
  inline std::string get_type_name(type_tag<t_std>) { \
    return std::is_same<t_std, t_bit>::value ? #t_bit : #t_std; \
  }

I feel like with this implementation output for other class templates will be messy.

True

We could rather prefer bit size variant over the standard types when std::is_same_v<int, int32_t> evaluates to true and register all such associations using a macro as you suggested here.

Sounds good to me!