text: //
  // Copyright 2018 The ANGLE Project Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  //
  // BlobCache: Stores compiled and linked programs in memory so they don't
  //   always have to be re-compiled. Can be used in conjunction with the platform
  //   layer to warm up the cache from disk.
  
  #ifndef LIBANGLE_BLOB_CACHE_H_
  #define LIBANGLE_BLOB_CACHE_H_
  
  #include <array>
  #include <cstring>
  
  #include <anglebase/sha1.h>
  #include "common/MemoryBuffer.h"
  #include "common/hash_utils.h"
  #include "libANGLE/Error.h"
  #include "libANGLE/SizedMRUCache.h"
  
  namespace gl
  {
  class Context;
  }  // namespace gl
  
  namespace egl
  {
  // 160-bit SHA-1 hash key used for hasing a program.  BlobCache opts in using fixed keys for
  // simplicity and efficiency.
  static constexpr size_t kBlobCacheKeyLength = angle::base::kSHA1Length;
  using BlobCacheKey                          = std::array<uint8_t, kBlobCacheKeyLength>;
  }  // namespace egl
  
  namespace std
  {
  template <>
  struct hash<egl::BlobCacheKey>
  {
      // Simple routine to hash four ints.
      size_t operator()(const egl::BlobCacheKey &key) const
      {
          return angle::ComputeGenericHash(key.data(), key.size());
      }
  };
  }  // namespace std
  
  namespace egl
  {
  
  class BlobCache final : angle::NonCopyable
  {
    public:
      // 160-bit SHA-1 hash key used for hasing a program.  BlobCache opts in using fixed keys for
      // simplicity and efficiency.
      static constexpr size_t kKeyLength = kBlobCacheKeyLength;
      using Key                          = BlobCacheKey;
      class Value
      {
        public:
          Value() : mPtr(nullptr), mSize(0) {}
          Value(const uint8_t *ptr, size_t sz) : mPtr(ptr), mSize(sz) {}
  
          // A very basic struct to hold the pointer and size together.  The objects of this class
          // don't own the memory.
          const uint8_t *data() { return mPtr; }
          size_t size() { return mSize; }
  
          const uint8_t &operator[](size_t pos) const
          {
              ASSERT(pos < mSize);
              return mPtr[pos];
          }
  
        private:
          const uint8_t *mPtr;
          size_t mSize;
      };
      enum class CacheSource
      {
          Memory,
          Disk,
      };
  
      explicit BlobCache(size_t maxCacheSizeBytes);
      ~BlobCache();
  
      // Store a key-blob pair in the cache.  If application callbacks are set, the application cache
      // will be used.  Otherwise the value is cached in this object.
      void put(const BlobCache::Key &key, angle::MemoryBuffer &&value);
  
      // Store a key-blob pair in the application cache, only if application callbacks are set.
      void putApplication(const BlobCache::Key &key, const angle::MemoryBuffer &value);
  
      // Store a key-blob pair in the cache without making callbacks to the application.  This is used
      // to repopulate this object's cache on startup without generating callback calls.
      void populate(const BlobCache::Key &key,
                    angle::MemoryBuffer &&value,
                    CacheSource source = CacheSource::Disk);
  
      // Check if the cache contains the blob corresponding to this key.  If application callbacks are
      // set, those will be used.  Otherwise they key is looked up in this object's cache.
      ANGLE_NO_DISCARD bool get(angle::ScratchBuffer *scratchBuffer,
                                const BlobCache::Key &key,
                                BlobCache::Value *valueOut,
                                size_t *bufferSizeOut);
  
      // For querying the contents of the cache.
      ANGLE_NO_DISCARD bool getAt(size_t index,
                                  const BlobCache::Key **keyOut,
                                  BlobCache::Value *valueOut);
  
      // Evict a blob from the binary cache.
      void remove(const BlobCache::Key &key);
  
      // Empty the cache.
      void clear() { mBlobCache.clear(); }
  
      // Resize the cache. Discards current contents.
      void resize(size_t maxCacheSizeBytes) { mBlobCache.resize(maxCacheSizeBytes); }
  
      // Returns the number of entries in the cache.
      size_t entryCount() const { return mBlobCache.entryCount(); }
  
      // Reduces the current cache size and returns the number of bytes freed.
      size_t trim(size_t limit) { return mBlobCache.shrinkToSize(limit); }
  
      // Returns the current cache size in bytes.
      size_t size() const { return mBlobCache.size(); }
  
      // Returns whether the cache is empty
      bool empty() const { return mBlobCache.empty(); }
  
      // Returns the maximum cache size in bytes.
      size_t maxSize() const { return mBlobCache.maxSize(); }
  
      void setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
  
      bool areBlobCacheFuncsSet() const;
  
      bool isCachingEnabled() const { return areBlobCacheFuncsSet() || maxSize() > 0; }
  
    private:
      // This internal cache is used only if the application is not providing caching callbacks
      using CacheEntry = std::pair<angle::MemoryBuffer, CacheSource>;
      angle::SizedMRUCache<BlobCache::Key, CacheEntry> mBlobCache;
  
      EGLSetBlobFuncANDROID mSetBlobFunc;
      EGLGetBlobFuncANDROID mGetBlobFunc;
  };
  
  }  // namespace egl
  
  #endif  // LIBANGLE_MEMORY_PROGRAM_CACHE_H_
  