// Copyright 2020 The Dawn 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 DAWNNATIVE_PERSISTENTCACHE_H_
#define DAWNNATIVE_PERSISTENTCACHE_H_

#include "dawn_native/Error.h"

#include <mutex>
#include <vector>

namespace dawn::platform {
    class CachingInterface;
}

namespace dawn_native {

    using PersistentCacheKey = std::vector<uint8_t>;

    struct ScopedCachedBlob {
        std::unique_ptr<uint8_t[]> buffer;
        size_t bufferSize = 0;
    };

    class DeviceBase;

    enum class PersistentKeyType { Shader };

    // This class should always be thread-safe as it is used in Create*PipelineAsync() where it is
    // called asynchronously.
    // The thread-safety of any access to mCache (the function LoadData() and StoreData()) is
    // protected by mMutex.
    class PersistentCache {
      public:
        PersistentCache(DeviceBase* device);

        // Combines load/store operations into a single call.
        // If the load was successful, a non-empty blob is returned to the caller.
        // Else, the creation callback |createFn| gets invoked with a callback
        // |doCache| to store the newly created blob back in the cache.
        //
        // Example usage:
        //
        // ScopedCachedBlob cachedBlob = {};
        // DAWN_TRY_ASSIGN(cachedBlob, GetOrCreate(key, [&](auto doCache)) {
        //      // Create a new blob to be stored
        //      doCache(newBlobPtr, newBlobSize); // store
        // }));
        //
        template <typename CreateFn>
        ResultOrError<ScopedCachedBlob> GetOrCreate(const PersistentCacheKey& key,
                                                    CreateFn&& createFn) {
            // Attempt to load an existing blob from the cache.
            ScopedCachedBlob blob = LoadData(key);
            if (blob.bufferSize > 0) {
                return std::move(blob);
            }

            // Allow the caller to create a new blob to be stored for the given key.
            DAWN_TRY(createFn([this, key](const void* value, size_t size) {
                this->StoreData(key, value, size);
            }));

            return std::move(blob);
        }

      private:
        // PersistentCache impl
        ScopedCachedBlob LoadData(const PersistentCacheKey& key);
        void StoreData(const PersistentCacheKey& key, const void* value, size_t size);

        dawn::platform::CachingInterface* GetPlatformCache();

        DeviceBase* mDevice = nullptr;

        std::mutex mMutex;
        dawn::platform::CachingInterface* mCache = nullptr;
    };
}  // namespace dawn_native

#endif  // DAWNNATIVE_PERSISTENTCACHE_H_
