forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			168 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			168 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 13; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* vim: set ts=13 sts=2 et sw=2 tw=80: */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#ifndef MOZILLA_CACHE_INVALIDATOR_H_
 | 
						|
#define MOZILLA_CACHE_INVALIDATOR_H_
 | 
						|
 | 
						|
#include "mozilla/Maybe.h"
 | 
						|
#include "mozilla/UniquePtr.h"
 | 
						|
#include <unordered_map>
 | 
						|
#include <unordered_set>
 | 
						|
#include <vector>
 | 
						|
 | 
						|
// -
 | 
						|
 | 
						|
namespace mozilla {
 | 
						|
 | 
						|
class AbstractCache;
 | 
						|
 | 
						|
// -
 | 
						|
 | 
						|
class CacheInvalidator {
 | 
						|
  friend class AbstractCache;
 | 
						|
 | 
						|
 private:
 | 
						|
  mutable std::unordered_set<AbstractCache*> mCaches;
 | 
						|
 | 
						|
 public:
 | 
						|
  virtual ~CacheInvalidator() {
 | 
						|
    // It's actually generally unsafe to wait until now to invalidate caches,
 | 
						|
    // because when used as a mixin, this dtor is called after the dtor for the
 | 
						|
    // derived class. This means that if the derived class holds a cache (or is
 | 
						|
    // a cache!), OnInvalidate() will be called on a destroyed object.
 | 
						|
    // MOZ_ASSERT(!mCaches);
 | 
						|
    InvalidateCaches();
 | 
						|
  }
 | 
						|
 | 
						|
  void InvalidateCaches() const;
 | 
						|
};
 | 
						|
 | 
						|
// -
 | 
						|
 | 
						|
class AbstractCache {
 | 
						|
  using InvalidatorListT = std::vector<const CacheInvalidator*>;
 | 
						|
 | 
						|
 private:
 | 
						|
  InvalidatorListT mInvalidators;
 | 
						|
 | 
						|
 public:
 | 
						|
  AbstractCache() = default;
 | 
						|
 | 
						|
  explicit AbstractCache(InvalidatorListT&& invalidators) {
 | 
						|
    ResetInvalidators(std::move(invalidators));
 | 
						|
  }
 | 
						|
 | 
						|
  virtual ~AbstractCache() { ResetInvalidators({}); }
 | 
						|
 | 
						|
 public:
 | 
						|
  virtual void OnInvalidate() = 0;
 | 
						|
 | 
						|
  void ResetInvalidators(InvalidatorListT&&);
 | 
						|
  void AddInvalidator(const CacheInvalidator&);
 | 
						|
};
 | 
						|
 | 
						|
// -
 | 
						|
 | 
						|
template <typename T>
 | 
						|
class CacheMaybe : public AbstractCache {
 | 
						|
  Maybe<T> mVal;
 | 
						|
 | 
						|
 public:
 | 
						|
  template <typename U>
 | 
						|
  CacheMaybe& operator=(Maybe<U>&& rhs) {
 | 
						|
    mVal.reset();
 | 
						|
    if (rhs) {
 | 
						|
      mVal.emplace(std::move(rhs.ref()));
 | 
						|
    }
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
 | 
						|
  CacheMaybe& operator=(Nothing) { return *this = Maybe<T>(); }
 | 
						|
 | 
						|
  void OnInvalidate() override {
 | 
						|
    *this = Nothing();
 | 
						|
    ResetInvalidators({});
 | 
						|
  }
 | 
						|
 | 
						|
  explicit operator bool() const { return bool(mVal); }
 | 
						|
  T* get() const { return mVal.ptrOr(nullptr); }
 | 
						|
  T* operator->() const { return get(); }
 | 
						|
};
 | 
						|
 | 
						|
// -
 | 
						|
 | 
						|
template <typename KeyT, typename ValueT>
 | 
						|
class CacheWeakMap final {
 | 
						|
  class Entry final : public AbstractCache {
 | 
						|
   public:
 | 
						|
    CacheWeakMap& mParent;
 | 
						|
    const KeyT mKey;
 | 
						|
    const ValueT mValue;
 | 
						|
 | 
						|
    Entry(CacheWeakMap& parent, const KeyT& key, ValueT&& value)
 | 
						|
        : mParent(parent), mKey(key), mValue(std::move(value)) {}
 | 
						|
 | 
						|
    void OnInvalidate() override {
 | 
						|
      const auto erased = mParent.mMap.erase(&mKey);
 | 
						|
      MOZ_ALWAYS_TRUE(erased == 1);
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  struct DerefHash final {
 | 
						|
    size_t operator()(const KeyT* const a) const {
 | 
						|
      return std::hash<KeyT>()(*a);
 | 
						|
    }
 | 
						|
  };
 | 
						|
  struct DerefEqual final {
 | 
						|
    bool operator()(const KeyT* const a, const KeyT* const b) const {
 | 
						|
      return *a == *b;
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  using MapT =
 | 
						|
      std::unordered_map<const KeyT*, UniquePtr<Entry>, DerefHash, DerefEqual>;
 | 
						|
  MapT mMap;
 | 
						|
 | 
						|
 public:
 | 
						|
  UniquePtr<Entry> MakeEntry(const KeyT& key, ValueT&& value) {
 | 
						|
    return UniquePtr<Entry>(new Entry(*this, key, std::move(value)));
 | 
						|
  }
 | 
						|
  UniquePtr<Entry> MakeEntry(const KeyT& key, const ValueT& value) {
 | 
						|
    return MakeEntry(key, ValueT(value));
 | 
						|
  }
 | 
						|
 | 
						|
  const ValueT* Insert(UniquePtr<Entry>&& entry) {
 | 
						|
    auto insertable = typename MapT::value_type{&entry->mKey, std::move(entry)};
 | 
						|
 | 
						|
    const auto res = mMap.insert(std::move(insertable));
 | 
						|
    const auto& didInsert = res.second;
 | 
						|
    MOZ_ALWAYS_TRUE(didInsert);
 | 
						|
 | 
						|
    const auto& itr = res.first;
 | 
						|
    return &itr->second->mValue;
 | 
						|
  }
 | 
						|
 | 
						|
  const ValueT* Find(const KeyT& key) const {
 | 
						|
    const auto itr = mMap.find(&key);
 | 
						|
    if (itr == mMap.end()) return nullptr;
 | 
						|
 | 
						|
    return &itr->second->mValue;
 | 
						|
  }
 | 
						|
 | 
						|
  void Clear() const {
 | 
						|
    while (true) {
 | 
						|
      const auto itr = mMap.begin();
 | 
						|
      if (itr == mMap.end()) return;
 | 
						|
      itr->second->OnInvalidate();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  ~CacheWeakMap() { Clear(); }
 | 
						|
};
 | 
						|
 | 
						|
}  // namespace mozilla
 | 
						|
 | 
						|
#endif  // MOZILLA_CACHE_INVALIDATOR_H_
 |