1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 18:38:10 +00:00

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.
This commit is contained in:
Sam Atkins 2022-04-27 12:46:22 +01:00 committed by Andreas Kling
parent 5c8ff96a94
commit a490f24a2d

View file

@ -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);