mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 12:22:44 +00:00 
			
		
		
		
	AK: Make HashTable and HashMap try_* functions return ErrorOr<T>
This allows us to use TRY() and MUST() with them.
This commit is contained in:
		
							parent
							
								
									4eaa95769d
								
							
						
					
					
						commit
						9d1f238450
					
				
					 3 changed files with 22 additions and 37 deletions
				
			
		|  | @ -49,8 +49,8 @@ public: | |||
| 
 | ||||
|     HashSetResult set(const K& key, const V& value) { return m_table.set({ key, value }); } | ||||
|     HashSetResult set(const K& key, V&& value) { return m_table.set({ key, move(value) }); } | ||||
|     HashSetResult try_set(const K& key, const V& value) { return m_table.try_set({ key, value }); } | ||||
|     HashSetResult try_set(const K& key, V&& value) { return m_table.try_set({ key, move(value) }); } | ||||
|     ErrorOr<HashSetResult> try_set(const K& key, const V& value) { return m_table.try_set({ key, value }); } | ||||
|     ErrorOr<HashSetResult> try_set(const K& key, V&& value) { return m_table.try_set({ key, move(value) }); } | ||||
| 
 | ||||
|     bool remove(const K& key) | ||||
|     { | ||||
|  | @ -91,7 +91,7 @@ public: | |||
|     } | ||||
| 
 | ||||
|     void ensure_capacity(size_t capacity) { m_table.ensure_capacity(capacity); } | ||||
|     bool try_ensure_capacity(size_t capacity) { return m_table.try_ensure_capacity(capacity); } | ||||
|     ErrorOr<void> try_ensure_capacity(size_t capacity) { return m_table.try_ensure_capacity(capacity); } | ||||
| 
 | ||||
|     Optional<typename Traits<V>::PeekType> get(const K& key) const requires(!IsPointer<typename Traits<V>::PeekType>) | ||||
|     { | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <AK/Error.h> | ||||
| #include <AK/Forward.h> | ||||
| #include <AK/HashFunctions.h> | ||||
| #include <AK/StdLibExtras.h> | ||||
|  | @ -16,7 +17,6 @@ | |||
| namespace AK { | ||||
| 
 | ||||
| enum class HashSetResult { | ||||
|     Failed = 0, | ||||
|     InsertedNewEntry, | ||||
|     ReplacedExistingEntry, | ||||
|     KeptExistingEntry | ||||
|  | @ -186,19 +186,16 @@ public: | |||
|     [[nodiscard]] size_t capacity() const { return m_capacity; } | ||||
| 
 | ||||
|     template<typename U, size_t N> | ||||
|     bool try_set_from(U (&from_array)[N]) | ||||
|     ErrorOr<void> try_set_from(U (&from_array)[N]) | ||||
|     { | ||||
|         for (size_t i = 0; i < N; ++i) { | ||||
|             if (try_set(from_array[i]) == HashSetResult::Failed) | ||||
|                 return false; | ||||
|         } | ||||
|         return true; | ||||
|         for (size_t i = 0; i < N; ++i) | ||||
|             TRY(try_set(from_array[i])); | ||||
|         return {}; | ||||
|     } | ||||
|     template<typename U, size_t N> | ||||
|     void set_from(U (&from_array)[N]) | ||||
|     { | ||||
|         bool result = try_set_from(from_array); | ||||
|         VERIFY(result); | ||||
|         MUST(try_set_from(from_array)); | ||||
|     } | ||||
| 
 | ||||
|     void ensure_capacity(size_t capacity) | ||||
|  | @ -260,11 +257,9 @@ public: | |||
|     } | ||||
| 
 | ||||
|     template<typename U = T> | ||||
|     HashSetResult try_set(U&& value, HashSetExistingEntryBehavior existing_entry_behavior = HashSetExistingEntryBehavior::Replace) | ||||
|     ErrorOr<HashSetResult> try_set(U&& value, HashSetExistingEntryBehavior existing_entry_behavior = HashSetExistingEntryBehavior::Replace) | ||||
|     { | ||||
|         auto* bucket = try_lookup_for_writing(value); | ||||
|         if (!bucket) | ||||
|             return HashSetResult::Failed; | ||||
|         auto* bucket = TRY(try_lookup_for_writing(value)); | ||||
|         if (bucket->used) { | ||||
|             if (existing_entry_behavior == HashSetExistingEntryBehavior::Keep) | ||||
|                 return HashSetResult::KeptExistingEntry; | ||||
|  | @ -295,9 +290,7 @@ public: | |||
|     template<typename U = T> | ||||
|     HashSetResult set(U&& value, HashSetExistingEntryBehavior existing_entry_behaviour = HashSetExistingEntryBehavior::Replace) | ||||
|     { | ||||
|         auto result = try_set(forward<U>(value), existing_entry_behaviour); | ||||
|         VERIFY(result != HashSetResult::Failed); | ||||
|         return result; | ||||
|         return MUST(try_set(forward<U>(value), existing_entry_behaviour)); | ||||
|     } | ||||
| 
 | ||||
|     template<typename TUnaryPredicate> | ||||
|  | @ -388,7 +381,7 @@ private: | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     bool try_rehash(size_t new_capacity) | ||||
|     ErrorOr<void> try_rehash(size_t new_capacity) | ||||
|     { | ||||
|         new_capacity = max(new_capacity, static_cast<size_t>(4)); | ||||
|         new_capacity = kmalloc_good_size(new_capacity * sizeof(BucketType)) / sizeof(BucketType); | ||||
|  | @ -399,7 +392,7 @@ private: | |||
| 
 | ||||
|         auto new_buckets = kmalloc(size_in_bytes(new_capacity)); | ||||
|         if (!new_buckets) | ||||
|             return false; | ||||
|             return Error::from_errno(ENOMEM); | ||||
| 
 | ||||
|         m_buckets = (BucketType*)new_buckets; | ||||
|         __builtin_memset(m_buckets, 0, size_in_bytes(new_capacity)); | ||||
|  | @ -413,7 +406,7 @@ private: | |||
|             m_buckets[m_capacity].end = true; | ||||
| 
 | ||||
|         if (!old_buckets) | ||||
|             return true; | ||||
|             return {}; | ||||
| 
 | ||||
|         for (auto it = move(old_iter); it != end(); ++it) { | ||||
|             insert_during_rehash(move(*it)); | ||||
|  | @ -421,12 +414,11 @@ private: | |||
|         } | ||||
| 
 | ||||
|         kfree_sized(old_buckets, size_in_bytes(old_capacity)); | ||||
|         return true; | ||||
|         return {}; | ||||
|     } | ||||
|     void rehash(size_t new_capacity) | ||||
|     { | ||||
|         bool result = try_rehash(new_capacity); | ||||
|         VERIFY(result); | ||||
|         MUST(try_rehash(new_capacity)); | ||||
|     } | ||||
| 
 | ||||
|     template<typename TUnaryPredicate> | ||||
|  | @ -448,15 +440,13 @@ private: | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] BucketType* try_lookup_for_writing(T const& value) | ||||
|     ErrorOr<BucketType*> try_lookup_for_writing(T const& value) | ||||
|     { | ||||
|         // FIXME: Maybe overrun the "allowed" load factor to avoid OOM
 | ||||
|         //        If we are allowed to do that, separate that logic from
 | ||||
|         //        the normal lookup_for_writing
 | ||||
|         if (should_grow()) { | ||||
|             if (!try_rehash(capacity() * 2)) | ||||
|                 return nullptr; | ||||
|         } | ||||
|         if (should_grow()) | ||||
|             TRY(try_rehash(capacity() * 2)); | ||||
|         auto hash = TraitsForT::hash(value); | ||||
|         BucketType* first_empty_bucket = nullptr; | ||||
|         for (;;) { | ||||
|  | @ -478,9 +468,7 @@ private: | |||
|     } | ||||
|     [[nodiscard]] BucketType& lookup_for_writing(T const& value) | ||||
|     { | ||||
|         auto* item = try_lookup_for_writing(value); | ||||
|         VERIFY(item); | ||||
|         return *item; | ||||
|         return *MUST(try_lookup_for_writing(value)); | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] size_t used_bucket_count() const { return m_size + m_deleted_count; } | ||||
|  |  | |||
|  | @ -315,10 +315,7 @@ void PerformanceEventBuffer::add_process(const Process& process, ProcessEventTyp | |||
| ErrorOr<FlatPtr> PerformanceEventBuffer::register_string(NonnullOwnPtr<KString> string) | ||||
| { | ||||
|     FlatPtr string_id = m_strings.size(); | ||||
| 
 | ||||
|     if (m_strings.try_set(move(string)) == AK::HashSetResult::Failed) | ||||
|         return ENOBUFS; | ||||
| 
 | ||||
|     TRY(m_strings.try_set(move(string))); | ||||
|     return string_id; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling