Compare commits

...

1 Commits

Author SHA1 Message Date
John Ericson
adcbf3e19a WIP strip strings at compile time 2025-11-17 14:32:33 -05:00
5 changed files with 76 additions and 45 deletions

View File

@@ -114,4 +114,69 @@ std::string dropEmptyInitThenConcatStringsSep(const std::string_view sep, const
return s;
}
/**
* Consteval helper for the "constexpr 2-step" pattern.
* Converts a std::string to a std::array<char, N> for stable compile-time storage.
*
* Usage:
* static constexpr auto str = stripIndentationConsteval(...);
* static constexpr auto arr = toArray<str.size()>(str);
* static constexpr std::string_view view{arr.data(), arr.size()};
*/
template<size_t N>
consteval std::string_view toArray(const std::string & s)
{
static std::array<char, N> arr{};
for (size_t i = 0; i < N; ++i) {
arr[i] = s[i];
}
return {arr.data(), N};
}
constexpr std::string stripIndentationImpl(std::string_view s)
{
size_t minIndent = 10000;
size_t curIndent = 0;
bool atStartOfLine = true;
for (auto & c : s) {
if (atStartOfLine && c == ' ')
curIndent++;
else if (c == '\n') {
if (atStartOfLine)
minIndent = std::max(minIndent, curIndent);
curIndent = 0;
atStartOfLine = true;
} else {
if (atStartOfLine) {
minIndent = std::min(minIndent, curIndent);
atStartOfLine = false;
}
}
}
std::string res;
size_t pos = 0;
while (pos < s.size()) {
auto eol = s.find('\n', pos);
if (eol == s.npos)
eol = s.size();
if (eol - pos > minIndent)
res.append(s.substr(pos + minIndent, eol - pos - minIndent));
res.push_back('\n');
pos = eol + 1;
}
return res;
}
template<std::string_view s>
consteval std::string_view stripIndentationConsteval()
{
constexpr auto stripped = stripIndentationImpl(s);
constexpr size_t n = stripped.size();
return toArray<n>(stripped);
}
} // namespace nix

View File

@@ -132,6 +132,13 @@ std::string optionalBracket(std::string_view prefix, const std::optional<T> & co
return optionalBracket(prefix, std::string_view(*content), suffix);
}
/**
* Remove common leading whitespace from the lines in the string
* 's'. For example, if every line is indented by at least 3 spaces,
* then we remove 3 spaces from the start of every line.
*/
std::string stripIndentation(std::string_view s);
/**
* Hash implementation that can be used for zero-copy heterogenous lookup from
* P1690R1[1] in unordered containers.

View File

@@ -228,13 +228,6 @@ constexpr char treeLast[] = "└───";
constexpr char treeLine[] = "";
constexpr char treeNull[] = " ";
/**
* Remove common leading whitespace from the lines in the string
* 's'. For example, if every line is indented by at least 3 spaces,
* then we remove 3 spaces from the start of every line.
*/
std::string stripIndentation(std::string_view s);
/**
* Get the prefix of 's' up to and excluding the next line break (LF
* optionally preceded by CR), and the remainder following the line

View File

@@ -152,4 +152,8 @@ std::string optionalBracket(std::string_view prefix, std::string_view content, s
return result;
}
std::string stripIndentation(std::string_view s) {
return stripIndentationImpl(s);
}
} // namespace nix

View File

@@ -250,44 +250,6 @@ void ignoreExceptionExceptInterrupt(Verbosity lvl)
}
}
std::string stripIndentation(std::string_view s)
{
size_t minIndent = 10000;
size_t curIndent = 0;
bool atStartOfLine = true;
for (auto & c : s) {
if (atStartOfLine && c == ' ')
curIndent++;
else if (c == '\n') {
if (atStartOfLine)
minIndent = std::max(minIndent, curIndent);
curIndent = 0;
atStartOfLine = true;
} else {
if (atStartOfLine) {
minIndent = std::min(minIndent, curIndent);
atStartOfLine = false;
}
}
}
std::string res;
size_t pos = 0;
while (pos < s.size()) {
auto eol = s.find('\n', pos);
if (eol == s.npos)
eol = s.size();
if (eol - pos > minIndent)
res.append(s.substr(pos + minIndent, eol - pos - minIndent));
res.push_back('\n');
pos = eol + 1;
}
return res;
}
std::pair<std::string_view, std::string_view> getLine(std::string_view s)
{
auto newline = s.find('\n');