| // Copyright 2021 The Tint Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef FUZZERS_TINT_SPIRV_TOOLS_FUZZER_MUTATOR_CACHE_H_ |
| #define FUZZERS_TINT_SPIRV_TOOLS_FUZZER_MUTATOR_CACHE_H_ |
| |
| #include <cassert> |
| #include <list> |
| #include <memory> |
| #include <unordered_map> |
| #include <utility> |
| #include <vector> |
| |
| #include "fuzzers/tint_spirv_tools_fuzzer/mutator.h" |
| |
| namespace tint { |
| namespace fuzzers { |
| namespace spvtools_fuzzer { |
| |
| /// Implementation of a fixed size LRU cache. That is, when the number of |
| /// elements reaches a certain threshold, the element that wasn't used for the |
| /// longest period of time is removed from the cache when a new element is |
| /// inserted. All operations have amortized constant time complexity. |
| class MutatorCache { |
| public: |
| /// SPIR-V binary that is being mutated. |
| using Key = std::vector<uint32_t>; |
| |
| /// Mutator that is used to mutate the `Key`. |
| using Value = std::unique_ptr<Mutator>; |
| |
| /// Constructor. |
| /// @param max_size - the maximum number of elements the cache can store. May |
| /// not be equal to 0. |
| explicit MutatorCache(size_t max_size); |
| |
| /// Retrieves a pointer to a value, associated with a given `key`. |
| /// |
| /// If the key is present in the cache, its usage is updated and the |
| /// (non-null) pointer to the value is returned. Otherwise, `nullptr` is |
| /// returned. |
| /// |
| /// @param key - may not exist in this cache. |
| /// @return non-`nullptr` pointer to a value if `key` exists in the cache. |
| /// @return `nullptr` if `key` doesn't exist in this cache. |
| Value::pointer Get(const Key& key); |
| |
| /// Inserts a `key`-`value` pair into the cache. |
| /// |
| /// If the `key` is already present, the `value` replaces the old value and |
| /// the usage of `key` is updated. If the `key` is not present, then: |
| /// - if the number of elements in the cache is equal to `max_size`, the |
| /// key-value pair, where the usage of the key wasn't updated for the |
| /// longest period of time, is removed from the cache. |
| /// - a new `key`-`value` pair is inserted into the cache. |
| /// |
| /// @param key - a key. |
| /// @param value - may not be a `nullptr`. |
| void Put(const Key& key, Value value); |
| |
| /// Removes `key` and an associated value from the cache. |
| /// |
| /// @param key - a key. |
| /// @return a non-`nullptr` pointer to the removed value, associated with |
| /// `key`. |
| /// @return `nullptr` if `key` is not present in the cache. |
| Value Remove(const Key& key); |
| |
| private: |
| struct KeyHash { |
| size_t operator()(const std::vector<uint32_t>& vec) const; |
| }; |
| |
| using Entry = std::pair<const Key*, Value>; |
| using Map = std::unordered_map<Key, std::list<Entry>::iterator, KeyHash>; |
| |
| void UpdateUsage(Map::iterator it); |
| |
| Map map_; |
| std::list<Entry> entries_; |
| const size_t max_size_; |
| }; |
| |
| } // namespace spvtools_fuzzer |
| } // namespace fuzzers |
| } // namespace tint |
| |
| #endif // FUZZERS_TINT_SPIRV_TOOLS_FUZZER_MUTATOR_CACHE_H_ |