// 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 #include #include #include #include #include #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; /// Mutator that is used to mutate the `Key`. using Value = std::unique_ptr; /// 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& vec) const; }; using Entry = std::pair; using Map = std::unordered_map::iterator, KeyHash>; void UpdateUsage(Map::iterator it); Map map_; std::list entries_; const size_t max_size_; }; } // namespace spvtools_fuzzer } // namespace fuzzers } // namespace tint #endif // FUZZERS_TINT_SPIRV_TOOLS_FUZZER_MUTATOR_CACHE_H_