summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@serenityos.org>2022-04-27 12:46:22 +0100
committerAndreas Kling <kling@serenityos.org>2022-04-29 00:07:31 +0200
commita490f24a2dff0dd03a2858472ee4a52be9c5986c (patch)
treef332df515afbd2bdccbadc27a16c5403b00af4e3
parent5c8ff96a94638427d00ec5ea720526277f0f8e10 (diff)
downloadserenity-a490f24a2dff0dd03a2858472ee4a52be9c5986c.zip
LibWeb: Add StateTransaction RAII to CSS TokenStream
This is modeled after the one in ISO8601Parser. It rolls back the TokenStream state automatically at the end of scope unless told to commit the changes. This should be less error-prone than remembering to manually call `rewind_to_position()` at the correct time. For convenience, a StateTransaction can have "child" transactions. When a transaction is committed, it automatically commits its parents too. This is useful in situations where you have several nested and don't want to have to remember to manually `commit()` them all.
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.h38
1 files changed, 38 insertions, 0 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
index 3df4321ec9..6617ffaedd 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
@@ -55,6 +55,43 @@ private:
template<typename T>
class TokenStream {
public:
+ class StateTransaction {
+ public:
+ explicit StateTransaction(TokenStream<T>& token_stream)
+ : m_token_stream(token_stream)
+ , m_saved_iterator_offset(token_stream.m_iterator_offset)
+ {
+ }
+
+ ~StateTransaction()
+ {
+ if (!m_commit)
+ m_token_stream.m_iterator_offset = m_saved_iterator_offset;
+ }
+
+ StateTransaction create_child() { return StateTransaction(*this); }
+
+ void commit()
+ {
+ m_commit = true;
+ if (m_parent)
+ m_parent->commit();
+ }
+
+ private:
+ explicit StateTransaction(StateTransaction& parent)
+ : m_parent(&parent)
+ , m_token_stream(parent.m_token_stream)
+ , m_saved_iterator_offset(parent.m_token_stream.m_iterator_offset)
+ {
+ }
+
+ StateTransaction* m_parent { nullptr };
+ TokenStream<T>& m_token_stream;
+ int m_saved_iterator_offset { 0 };
+ bool m_commit { false };
+ };
+
explicit TokenStream(Vector<T> const&);
~TokenStream() = default;
@@ -66,6 +103,7 @@ public:
T const& current_token();
void reconsume_current_input_token();
+ StateTransaction begin_transaction() { return StateTransaction(*this); }
int position() const { return m_iterator_offset; }
void rewind_to_position(int);