mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 09:52:44 +00:00 
			
		
		
		
	LibRegex: Use a copy-on-write vector for fork state
This commit is contained in:
		
							parent
							
								
									48a4c9c1ad
								
							
						
					
					
						commit
						f1851346d3
					
				
					 3 changed files with 140 additions and 8 deletions
				
			
		|  | @ -1060,9 +1060,11 @@ ALWAYS_INLINE ExecutionResult OpCode_Checkpoint::execute(MatchInput const& input | ||||||
| 
 | 
 | ||||||
| ALWAYS_INLINE ExecutionResult OpCode_JumpNonEmpty::execute(MatchInput const& input, MatchState& state) const | ALWAYS_INLINE ExecutionResult OpCode_JumpNonEmpty::execute(MatchInput const& input, MatchState& state) const | ||||||
| { | { | ||||||
|     auto current_position = state.string_position; |     u64 current_position = state.string_position; | ||||||
|     auto checkpoint_ip = state.instruction_position + size() + checkpoint(); |     auto checkpoint_ip = state.instruction_position + size() + checkpoint(); | ||||||
|     if (input.checkpoints.get(checkpoint_ip).value_or(current_position) != current_position) { |     auto checkpoint_position = input.checkpoints.find(checkpoint_ip); | ||||||
|  | 
 | ||||||
|  |     if (checkpoint_position != input.checkpoints.end() && checkpoint_position->value != current_position) { | ||||||
|         auto form = this->form(); |         auto form = this->form(); | ||||||
| 
 | 
 | ||||||
|         if (form == OpCodeId::Jump) { |         if (form == OpCodeId::Jump) { | ||||||
|  |  | ||||||
|  | @ -12,6 +12,7 @@ | ||||||
| #include <AK/FlyString.h> | #include <AK/FlyString.h> | ||||||
| #include <AK/HashMap.h> | #include <AK/HashMap.h> | ||||||
| #include <AK/MemMem.h> | #include <AK/MemMem.h> | ||||||
|  | #include <AK/RedBlackTree.h> | ||||||
| #include <AK/String.h> | #include <AK/String.h> | ||||||
| #include <AK/StringBuilder.h> | #include <AK/StringBuilder.h> | ||||||
| #include <AK/StringView.h> | #include <AK/StringView.h> | ||||||
|  | @ -23,6 +24,135 @@ | ||||||
| 
 | 
 | ||||||
| namespace regex { | namespace regex { | ||||||
| 
 | 
 | ||||||
|  | template<typename T> | ||||||
|  | class COWVector { | ||||||
|  |     struct Detail : RefCounted<Detail> { | ||||||
|  |         Vector<T> m_members; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     COWVector() | ||||||
|  |         : m_detail(make_ref_counted<Detail>()) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     COWVector(COWVector const&) = default; | ||||||
|  |     COWVector(COWVector&&) = default; | ||||||
|  | 
 | ||||||
|  |     COWVector& operator=(COWVector const&) = default; | ||||||
|  |     COWVector& operator=(COWVector&&) = default; | ||||||
|  | 
 | ||||||
|  |     Vector<T> release() && | ||||||
|  |     { | ||||||
|  |         if (m_detail->ref_count() == 1) | ||||||
|  |             return exchange(m_detail->m_members, Vector<T>()); | ||||||
|  | 
 | ||||||
|  |         return m_detail->m_members; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void append(T const& value) | ||||||
|  |     { | ||||||
|  |         return append(T { value }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void append(T&& value) | ||||||
|  |     { | ||||||
|  |         copy(); | ||||||
|  |         m_detail->m_members.append(move(value)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void resize(size_t size) | ||||||
|  |     { | ||||||
|  |         copy(); | ||||||
|  |         m_detail->m_members.resize(size); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void ensure_capacity(size_t capacity) | ||||||
|  |     { | ||||||
|  |         if (m_detail->m_members.capacity() >= capacity) | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         copy(); | ||||||
|  |         m_detail->m_members.ensure_capacity(capacity); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     template<typename... Args> | ||||||
|  |     void empend(Args&&... args) | ||||||
|  |     { | ||||||
|  |         copy(); | ||||||
|  |         m_detail->m_members.empend(forward<Args>(args)...); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void clear() | ||||||
|  |     { | ||||||
|  |         if (m_detail->ref_count() > 1) | ||||||
|  |             m_detail = make_ref_counted<Detail>(); | ||||||
|  |         else | ||||||
|  |             m_detail->m_members.clear(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     T& at(size_t index) | ||||||
|  |     { | ||||||
|  |         // We're handing out a mutable reference, so make sure we own the data exclusively.
 | ||||||
|  |         copy(); | ||||||
|  |         return m_detail->m_members.at(index); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     T const& at(size_t index) const | ||||||
|  |     { | ||||||
|  |         return m_detail->m_members.at(index); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     T& operator[](size_t index) | ||||||
|  |     { | ||||||
|  |         // We're handing out a mutable reference, so make sure we own the data exclusively.
 | ||||||
|  |         copy(); | ||||||
|  |         return m_detail->m_members[index]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     T const& operator[](size_t index) const | ||||||
|  |     { | ||||||
|  |         return m_detail->m_members[index]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     size_t capacity() const | ||||||
|  |     { | ||||||
|  |         return m_detail->m_members.capacity(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     size_t size() const | ||||||
|  |     { | ||||||
|  |         return m_detail->m_members.size(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool is_empty() const | ||||||
|  |     { | ||||||
|  |         return m_detail->m_members.is_empty(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     T const& first() const | ||||||
|  |     { | ||||||
|  |         return m_detail->m_members.first(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     T const& last() const | ||||||
|  |     { | ||||||
|  |         return m_detail->m_members.last(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     void copy() | ||||||
|  |     { | ||||||
|  |         if (m_detail->ref_count() <= 1) | ||||||
|  |             return; | ||||||
|  |         auto new_detail = make_ref_counted<Detail>(); | ||||||
|  |         new_detail->m_members = m_detail->m_members; | ||||||
|  |         m_detail = new_detail; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     NonnullRefPtr<Detail> m_detail; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| class RegexStringView { | class RegexStringView { | ||||||
| public: | public: | ||||||
|     RegexStringView() = default; |     RegexStringView() = default; | ||||||
|  | @ -510,9 +640,9 @@ struct MatchState { | ||||||
|     size_t fork_at_position { 0 }; |     size_t fork_at_position { 0 }; | ||||||
|     size_t forks_since_last_save { 0 }; |     size_t forks_since_last_save { 0 }; | ||||||
|     Optional<size_t> initiating_fork; |     Optional<size_t> initiating_fork; | ||||||
|     Vector<Match> matches; |     COWVector<Match> matches; | ||||||
|     Vector<Vector<Match>> capture_group_matches; |     COWVector<Vector<Match>> capture_group_matches; | ||||||
|     Vector<u64> repetition_marks; |     COWVector<u64> repetition_marks; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -156,7 +156,7 @@ RegexResult Matcher<Parser>::match(Vector<RegexStringView> const& views, Optiona | ||||||
| 
 | 
 | ||||||
|         for (size_t j = 0; j < c_match_preallocation_count; ++j) { |         for (size_t j = 0; j < c_match_preallocation_count; ++j) { | ||||||
|             state.matches.empend(); |             state.matches.empend(); | ||||||
|             state.capture_group_matches.unchecked_append({}); |             state.capture_group_matches.empend(); | ||||||
|             state.capture_group_matches.at(j).ensure_capacity(capture_groups_count); |             state.capture_group_matches.at(j).ensure_capacity(capture_groups_count); | ||||||
|             for (size_t k = 0; k < capture_groups_count; ++k) |             for (size_t k = 0; k < capture_groups_count; ++k) | ||||||
|                 state.capture_group_matches.at(j).unchecked_append({}); |                 state.capture_group_matches.at(j).unchecked_append({}); | ||||||
|  | @ -306,8 +306,8 @@ RegexResult Matcher<Parser>::match(Vector<RegexStringView> const& views, Optiona | ||||||
|     RegexResult result { |     RegexResult result { | ||||||
|         match_count != 0, |         match_count != 0, | ||||||
|         match_count, |         match_count, | ||||||
|         move(state.matches), |         move(state.matches).release(), | ||||||
|         move(state.capture_group_matches), |         move(state.capture_group_matches).release(), | ||||||
|         operations, |         operations, | ||||||
|         m_pattern->parser_result.capture_groups_count, |         m_pattern->parser_result.capture_groups_count, | ||||||
|         m_pattern->parser_result.named_capture_groups_count, |         m_pattern->parser_result.named_capture_groups_count, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Ali Mohammad Pur
						Ali Mohammad Pur