RawPath::Iter improvements
- Add direct accessors to RawPath::Iter for verbs and points. When not using a range-for, it's awkward to have to use "*iter" and then pick pieces out of the resulting tuple. It's also a tiny bit faster to access the type of points directly (i.e., "linePts()", "cubicPts()"), if we're already in a switch and already know the verb anyway, as opposed to having the iterator also check the verb in a generic accessor.
- Update RawPath::end() to also return the correct ending pointer for the points, not just for the verbs.
Diffs=
87f079a10 RawPath::Iter improvements
diff --git a/.rive_head b/.rive_head
index f5c51d2..ecf6ff9 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-1e80ad08ff12ac794ad0abe65022ba0d10df0c5b
+87f079a103eb417091b94ea5ed7eecd90cbc6149
diff --git a/include/rive/math/raw_path.hpp b/include/rive/math/raw_path.hpp
index f441917..2536aad 100644
--- a/include/rive/math/raw_path.hpp
+++ b/include/rive/math/raw_path.hpp
@@ -90,19 +90,58 @@
Iter() = default;
Iter(const PathVerb* verbs, const Vec2D* pts) : m_verbs(verbs), m_pts(pts) {}
- bool operator!=(const Iter& that) const { return m_verbs != that.m_verbs; }
- bool operator==(const Iter& that) const { return m_verbs == that.m_verbs; }
-
- PathVerb peekVerb() const { return *m_verbs; }
-
- std::tuple<const PathVerb, const Vec2D* const> operator*() const
+ bool operator!=(const Iter& that) const
{
- PathVerb verb = peekVerb();
+ assert(m_verbs != that.m_verbs || m_pts == that.m_pts);
+ return m_verbs != that.m_verbs;
+ }
+ bool operator==(const Iter& that) const
+ {
+ assert(m_verbs != that.m_verbs || m_pts == that.m_pts);
+ return m_verbs == that.m_verbs;
+ }
+
+ // Generic accessors. The points pointer is adjusted to point to p0 for each specific verb.
+ PathVerb verb() const { return *m_verbs; }
+ const Vec2D* pts() const { return m_pts + PtsBacksetForVerb(verb()); }
+ std::tuple<PathVerb, const Vec2D*> operator*() const
+ {
+ PathVerb verb = *m_verbs;
return {verb, m_pts + PtsBacksetForVerb(verb)};
}
- Iter& operator++()
- { // ++iter
+ // Specific point accessors for callers who already know the verb. (These may be a tiny bit
+ // faster in some cases since the iterator doesn't have to check the verb.)
+ Vec2D movePt() const
+ {
+ assert(verb() == PathVerb::move);
+ return m_pts[0];
+ }
+ const Vec2D* linePts() const
+ {
+ assert(verb() == PathVerb::line);
+ return m_pts - 1;
+ }
+ const Vec2D* quadPts() const
+ {
+ assert(verb() == PathVerb::quad);
+ return m_pts - 1;
+ }
+ const Vec2D* cubicPts() const
+ {
+ assert(verb() == PathVerb::cubic);
+ return m_pts - 1;
+ }
+ // P0 for a close can be accessed via rawPtsPtr()[-1]. Note than p1 for a close is not in
+ // the array at this location.
+
+ // Internal pointers held by the iterator. See PtsBacksetForVerb() for how pts() relates to
+ // the data for specific verbs.
+ const PathVerb* rawVerbsPtr() const { return m_verbs; }
+ const Vec2D* rawPtsPtr() const { return m_pts; }
+
+ Iter& operator++() // "++iter"
+ {
m_pts += PtsAdvanceAfterVerb(*m_verbs++);
return *this;
}
@@ -153,7 +192,10 @@
const Vec2D* m_pts;
};
Iter begin() const { return {m_Verbs.data(), m_Points.data()}; }
- Iter end() const { return {m_Verbs.data() + m_Verbs.size(), nullptr}; }
+ Iter end() const
+ {
+ return {m_Verbs.data() + m_Verbs.size(), m_Points.data() + m_Points.size()};
+ }
template <typename Handler> RawPath morph(Handler proc) const
{
diff --git a/test/raw_path_test.cpp b/test/raw_path_test.cpp
index 815ba2e..b992f61 100644
--- a/test/raw_path_test.cpp
+++ b/test/raw_path_test.cpp
@@ -91,9 +91,32 @@
std::vector<Vec2D> expectedPts)
{
REQUIRE(iter != end);
- PathVerb verb = std::get<0>(*iter);
- const Vec2D* pts = std::get<1>(*iter);
+ PathVerb verb = iter.verb();
+ const Vec2D* pts = iter.pts();
REQUIRE(verb == expectedVerb);
+ switch (verb)
+ {
+ case PathVerb::move:
+ CHECK(expectedPts.size() == 1);
+ CHECK(pts[0] == iter.movePt());
+ break;
+ case PathVerb::line:
+ CHECK(expectedPts.size() == 2);
+ CHECK(pts == iter.linePts());
+ break;
+ case PathVerb::quad:
+ CHECK(expectedPts.size() == 3);
+ CHECK(pts == iter.quadPts());
+ break;
+ case PathVerb::cubic:
+ CHECK(expectedPts.size() == 4);
+ CHECK(pts == iter.cubicPts());
+ break;
+ case PathVerb::close:
+ CHECK(expectedPts.size() == 0);
+ CHECK(pts == iter.rawPtsPtr() - 1);
+ break;
+ }
for (size_t i = 0; i < expectedPts.size(); ++i)
{
CHECK(pts[i] == expectedPts[i]);