port GrProxyProvider off SkTDynamicHash::Iter

This was the remaining tricky use of Iter,
removing elements from the table while iterating.

In this case, since we're removing everything, it looks
unnecessary... we can just clear the table when we're done.

Bug: skia:9703
Change-Id: I5333d9fade1e52bd82b5d9c6ac494aad068d5dd2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/277207
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
diff --git a/src/core/SkTDynamicHash.h b/src/core/SkTDynamicHash.h
index 4329ee7..aa2523d 100644
--- a/src/core/SkTDynamicHash.h
+++ b/src/core/SkTDynamicHash.h
@@ -122,11 +122,6 @@
     static T* Empty()   { return reinterpret_cast<T*>(0); }  // i.e. nullptr
     static T* Deleted() { return reinterpret_cast<T*>(1); }  // Also an invalid pointer.
 
-    // GrProxyProvider::removeAllUniqueKeys() uses Iter but removes elements from the table
-    // as it iterates, so it can't safely use foreach().
-    // TODO(mtklein): add mutate(), replace that use of Iter with that.
-    friend class GrProxyProvider;
-
     class Iter {
     public:
         explicit Iter(SkTDynamicHash* hash) : fHash(hash), fCurrentIndex(-1) {
diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp
index bc4e3ea..9f79983 100644
--- a/src/gpu/GrProxyProvider.cpp
+++ b/src/gpu/GrProxyProvider.cpp
@@ -843,6 +843,12 @@
 
 void GrProxyProvider::processInvalidUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy,
                                               InvalidateGPUResource invalidateGPUResource) {
+    this->processInvalidUniqueKeyImpl(key, proxy, invalidateGPUResource, RemoveTableEntry::kYes);
+}
+
+void GrProxyProvider::processInvalidUniqueKeyImpl(const GrUniqueKey& key, GrTextureProxy* proxy,
+                                                  InvalidateGPUResource invalidateGPUResource,
+                                                  RemoveTableEntry removeTableEntry) {
     SkASSERT(key.isValid());
 
     if (!proxy) {
@@ -865,7 +871,9 @@
     // Note: this method is called for the whole variety of GrGpuResources so often 'key'
     // will not be in 'fUniquelyKeyedProxies'.
     if (proxy) {
-        fUniquelyKeyedProxies.remove(key);
+        if (removeTableEntry == RemoveTableEntry::kYes) {
+            fUniquelyKeyedProxies.remove(key);
+        }
         proxy->cacheAccess().clearUniqueKey();
     }
 
@@ -897,13 +905,15 @@
 }
 
 void GrProxyProvider::removeAllUniqueKeys() {
-    UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies);
-    for (UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); !iter.done(); ++iter) {
-        GrTextureProxy& tmp = *iter;
-
-        this->processInvalidUniqueKey(tmp.getUniqueKey(), &tmp, InvalidateGPUResource::kNo);
-    }
-    SkASSERT(!fUniquelyKeyedProxies.count());
+    fUniquelyKeyedProxies.foreach([&](GrTextureProxy* proxy){
+        // It's not safe to remove table entries while iterating with foreach(),
+        // but since we're going to remove them all anyway, simply save that for the end.
+        this->processInvalidUniqueKeyImpl(proxy->getUniqueKey(), proxy,
+                                          InvalidateGPUResource::kNo,
+                                          RemoveTableEntry::kNo);
+    });
+    // Removing all those table entries is safe now.
+    fUniquelyKeyedProxies.reset();
 }
 
 bool GrProxyProvider::renderingDirectly() const {
diff --git a/src/gpu/GrProxyProvider.h b/src/gpu/GrProxyProvider.h
index 24d9363..e82146a 100644
--- a/src/gpu/GrProxyProvider.h
+++ b/src/gpu/GrProxyProvider.h
@@ -262,6 +262,12 @@
     friend class GrAHardwareBufferImageGenerator; // for createWrapped
     friend class GrResourceProvider; // for createWrapped
 
+    // processInvalidUniqueKey() with control over removing hash table entries,
+    // which is not safe while iterating with foreach().
+    enum class RemoveTableEntry { kNo, kYes };
+    void processInvalidUniqueKeyImpl(const GrUniqueKey&, GrTextureProxy*,
+                                     InvalidateGPUResource, RemoveTableEntry);
+
     bool isAbandoned() const;
 
     /*