diff --git a/CMakeLists.txt b/CMakeLists.txt index 995797b..5213f03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ set(CMAKE_COMPILE_WARNING_AS_ERROR ON) add_executable( trimja + src/all.natvis src/trimja.m.cpp src/allocationprofiler.cpp src/basicscope.cpp diff --git a/src/all.natvis b/src/all.natvis new file mode 100644 index 0000000..dcb8706 --- /dev/null +++ b/src/all.natvis @@ -0,0 +1,38 @@ + + + + + + + + + + + + + rawLength = *(const trimja::EvalString::Offset*)it + isVariable = (rawLength & mask) + length = rawLength & ~mask + + it + sizeof(trimja::EvalString::Offset),[length]s8b + + + it + sizeof(trimja::EvalString::Offset),[length]s8 + + it += length + sizeof(length) + + + + + + + + + + + + {{ end }} + {{ var = {m_pos + sizeof(trimja::EvalString::Offset),[length()]s8b} }} + {{ text = {m_pos + sizeof(trimja::EvalString::Offset),[length()]s8} }} + + diff --git a/src/evalstring.cpp b/src/evalstring.cpp index 8b34826..21d318c 100644 --- a/src/evalstring.cpp +++ b/src/evalstring.cpp @@ -28,9 +28,9 @@ // prefixed with the length of the segment, stored as an `Offset` type. The // leading bit of this is set to 1 if the segment is a variable, otherwise it is // 0 if the segment is text. Additionally there is an extra member variable -// `m_lastSegmentLength` that has the same value as the last `Offset`. This -// allows us to jump back to the last segment to extend it if it is a text -// segment. +// `m_lastTextSegmentLength` that has the length of the last text section or 0 +// if the last section was not text. This allows us to jump back to the last +// segment to extend it. // // This has the benefit that `EvalString` if very cache-friendly when iterating // and requires only one allocation. Moves and copies should be as cheap as @@ -101,18 +101,18 @@ bool operator!=(EvalString::const_iterator lhs, return !(lhs == rhs); } -EvalString::EvalString() : m_data(sizeof(Offset), '\0'), m_lastSegmentLength{} { +EvalString::EvalString() : m_data{}, m_lastTextSegmentLength{0} { assert(empty()); } void EvalString::clear() { - m_data.assign(sizeof(Offset), '\0'); - m_lastSegmentLength = 0; + m_data.clear(); + m_lastTextSegmentLength = 0; assert(empty()); } bool EvalString::empty() const { - return m_data.size() == sizeof(Offset); + return m_data.empty(); } EvalString::const_iterator EvalString::begin() const { @@ -124,27 +124,29 @@ EvalString::const_iterator EvalString::end() const { } void EvalString::appendText(std::string_view text) { - if (!hasLeadingBit(m_lastSegmentLength)) { + assert(!text.empty()); + if (m_lastTextSegmentLength > 0) { // If the last part was plain text we can extend it - const Offset newLength = m_lastSegmentLength + text.size(); + const Offset newLength = m_lastTextSegmentLength + text.size(); std::copy_n(reinterpret_cast(&newLength), sizeof(newLength), - m_data.end() - sizeof(Offset) - m_lastSegmentLength); + m_data.end() - sizeof(Offset) - m_lastTextSegmentLength); m_data.append(text); - m_lastSegmentLength = newLength; + m_lastTextSegmentLength = newLength; } else { // Otherwise write new segment - m_lastSegmentLength = text.size(); - m_data.append(reinterpret_cast(&m_lastSegmentLength), - sizeof(m_lastSegmentLength)); + const Offset length = text.size(); + m_data.append(reinterpret_cast(&length), sizeof(length)); m_data.append(text); + m_lastTextSegmentLength = length; } } void EvalString::appendVariable(std::string_view name) { - m_lastSegmentLength = setLeadingBit(name.size()); - m_data.append(reinterpret_cast(&m_lastSegmentLength), - sizeof(m_lastSegmentLength)); + assert(!name.empty()); + const Offset length = setLeadingBit(name.size()); + m_data.append(reinterpret_cast(&length), sizeof(length)); m_data.append(name); + m_lastTextSegmentLength = 0; } } // namespace trimja diff --git a/src/evalstring.h b/src/evalstring.h index a27f82f..494e2b6 100644 --- a/src/evalstring.h +++ b/src/evalstring.h @@ -42,7 +42,7 @@ class EvalString { private: std::string m_data; - Offset m_lastSegmentLength; + Offset m_lastTextSegmentLength; public: /** @@ -102,13 +102,13 @@ class EvalString { /** * @brief Appends text to the EvalString, consolidating consecutive text * sections. - * @param text The text to append. + * @param text The text to append. This must not be empty. */ void appendText(std::string_view text); /** * @brief Appends a variable to the EvalString. - * @param name The name of the variable to append. + * @param name The name of the variable to append. This must not be empty. */ void appendVariable(std::string_view name); }; diff --git a/tests/variables/build.ninja b/tests/variables/build.ninja index 8d6eba5..e31566a 100644 --- a/tests/variables/build.ninja +++ b/tests/variables/build.ninja @@ -4,7 +4,7 @@ pool bye depth = 100 foo = 42 rule copy - command = ninja --version $in -> $out foo=$foo bar=${bar} pool=$pool + command = ninja --version $in -> $out foo=$foo bar=${bar}$bar pool=$pool pool = hi build out1: copy in1 foo = 1