Search code examples
c++loggingstring-view

Can I repeat a std::string_view without copying when printing indentation?


I have a simple scene in C++ code. I want to get a long string containing some repeated std::string_view; is there a way to achieve this without copying the string?

#include <cstdio>
#include <string_view>

struct Logger {
    static inline constexpr std::string_view indent = "    ";
    static inline int level = 0;

    Logger() {
        level++;
    }

    // ...
    
    void log(const std::string &msg) {
        std::printf(/* repeat indent 'level' times */);
    }
};

Solution

  • C-Style Solution

    std::printf allows you to dynamically specify the field width. For example:

    #include <cstdio>
    
    int main() {
        int indent_length = 4;
        int indent_depth = 3;
    
        // note: "" is passed as an argument for %s
        std::printf("%*shi!", indent_length * indent_depth, "");
    }
    

    This will output:

                hi!
    

    We can use this trick because indentation always consist of one character, so we don't really have to repeat a full std::string_view. Obviously, this wouldn't work if you wanted indentation that is a mixture of multiple characters, but that would be highly unusual.

    Old-School C++ Solution

    However, that is a very C-style solution, and you could just use a loop to avoid copying:

    void log(std::string_view msg) {
        for (int i = 0; i < level; ++i) {
            std::cout << indent;
        }
        std::cout << msg;
    }
    

    However, if the indent is not a mixture of different characters, we can do a similar trick using std::cout as above to avoid this loop:

    void log(std::string_view msg) {
        std::cout << std::setw(indent_length * level) << "" << msg;
    }
    

    If you absolutely insist on using std::printf, we can still do:

    // if msg is always null-terminated
    std::printf("%s", msg.data());
    
    // otherwise
    std::printf("%.*s", int(msg.length()), msg.data());
    

    Your indent string can be printed exactly the same way.