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