Is there any way to make a substring at compile time, and NOT store the original string in the binary ?
I'm using std::experimental::source_location
, and really only need the filename, and not the full path, which ends up taking lots of space in the binary
Here's an example:
#include <iostream>
#include <experimental/source_location>
consteval std::string_view filename_only(
std::experimental::source_location location = std::experimental::source_location::current())
{
std::string_view s = location.file_name();
return s.substr(s.find_last_of('/')+1);
}
int main()
{
std::cout << "File: " << filename_only() << '\n';
}
https://godbolt.org/z/TqE7T87j3
The full string "/app/example.cpp" is stored, but only the file name is needed, so "/app/" is wasted memory.
Based on this, I ended up using the __FILE__
macro combined with the -fmacro-prefix-map
compiler option, instead of source_location
.
So I essentially use the following code
#include <cstdio>
#include <cstdint>
#define ERROR_LOG(s) log_impl(s, __FILE__, __LINE__);
void log_impl(const char* s, const char* file_name, uint16_t line)
{
printf("%s:%i\t\t%s", file_name, line, s);
}
int main()
{
ERROR_LOG("Uh-oh.")
}
with the following compiler option:
-fmacro-prefix-map=${SOURCE_DIR}/=/
I can verify that the constant strings stored in the binary do not include the full file path, as they did before, which was my objective.
Note that starting from GCC12, the macro __FILE_NAME__
should be available, making the use of the -fmacro-prefix-map
option redundant. I'm not using gcc 12 just yet, so the solution above is adequate.
Not sure if this is the most optimal way to do this, but with C++20 and its ability to use strings as template arguments, string can be trimmed at compile time like so:
namespace helpers_impl
{
template <size_t N>
struct fixed_string
{
char data[N];
template <size_t N1>
consteval fixed_string(const char (&str)[N1], size_t Trim)
{
for (size_t i = 0; i < N; ++i)
{
data[i] = str[i + Trim];
}
}
consteval fixed_string(const char (&str)[N])
{
for (size_t i = 0; i < N; ++i)
{
data[i] = str[i];
}
}
constexpr size_t size() const { return N - 1; }
constexpr char operator[](size_t i) const { return data[i]; }
};
template <fixed_string Str>
consteval size_t find_last_slash()
{
size_t last_index = 0;
for (size_t i = 0; i < Str.size(); ++i)
{
if (Str[i] == '/' || Str[i] == '\\')
{
last_index = i + 1;
}
}
return last_index;
}
template <fixed_string Str>
consteval auto get_file_name()
{
constexpr size_t idx = find_last_slash<Str>();
return fixed_string<Str.size() - idx + 1>(Str.data, idx);
}
}
#define FILE_NAME (([]{ return ::helpers_impl::get_file_name<__FILE__>(); })().data)
https://godbolt.org/z/83zjnYsWc
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With