blob: 90dd5ceeeb3ddd90e0c56b2e7e3dca0c53f6b6dc [file] [log] [blame]
// 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_