mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 07:32: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 | ||||
| { | ||||
|     auto current_position = state.string_position; | ||||
|     u64 current_position = state.string_position; | ||||
|     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(); | ||||
| 
 | ||||
|         if (form == OpCodeId::Jump) { | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ | |||
| #include <AK/FlyString.h> | ||||
| #include <AK/HashMap.h> | ||||
| #include <AK/MemMem.h> | ||||
| #include <AK/RedBlackTree.h> | ||||
| #include <AK/String.h> | ||||
| #include <AK/StringBuilder.h> | ||||
| #include <AK/StringView.h> | ||||
|  | @ -23,6 +24,135 @@ | |||
| 
 | ||||
| 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 { | ||||
| public: | ||||
|     RegexStringView() = default; | ||||
|  | @ -510,9 +640,9 @@ struct MatchState { | |||
|     size_t fork_at_position { 0 }; | ||||
|     size_t forks_since_last_save { 0 }; | ||||
|     Optional<size_t> initiating_fork; | ||||
|     Vector<Match> matches; | ||||
|     Vector<Vector<Match>> capture_group_matches; | ||||
|     Vector<u64> repetition_marks; | ||||
|     COWVector<Match> matches; | ||||
|     COWVector<Vector<Match>> capture_group_matches; | ||||
|     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) { | ||||
|             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); | ||||
|             for (size_t k = 0; k < capture_groups_count; ++k) | ||||
|                 state.capture_group_matches.at(j).unchecked_append({}); | ||||
|  | @ -306,8 +306,8 @@ RegexResult Matcher<Parser>::match(Vector<RegexStringView> const& views, Optiona | |||
|     RegexResult result { | ||||
|         match_count != 0, | ||||
|         match_count, | ||||
|         move(state.matches), | ||||
|         move(state.capture_group_matches), | ||||
|         move(state.matches).release(), | ||||
|         move(state.capture_group_matches).release(), | ||||
|         operations, | ||||
|         m_pattern->parser_result.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