Enable new ScopedReservation to inherit another.

Bug: b:233089187
Bug: b:237811834

Make it possible to create a new scoped reservation for the same
resource interface as another one - useful when the latter is not
available directly (this eliminates the need to propagate the interface
to where it is needed).
Also some clean-ups in the code/declarations.

Change-Id: I0e7f9f4bdbef593eab7c52fbec018715e629839b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3754714
Reviewed-by: Hong Xu <[email protected]>
Commit-Queue: Hong Xu <[email protected]>
Auto-Submit: Leonid Baraz <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1023479}
diff --git a/components/reporting/resources/resource_interface.cc b/components/reporting/resources/resource_interface.cc
index df8141a..4e7d32f 100644
--- a/components/reporting/resources/resource_interface.cc
+++ b/components/reporting/resources/resource_interface.cc
@@ -27,6 +27,17 @@
   size_ = size;
 }
 
+ScopedReservation::ScopedReservation(
+    uint64_t size,
+    const ScopedReservation& other_reservation) noexcept
+    : resource_interface_(other_reservation.resource_interface_) {
+  if (size == 0uL || !resource_interface_.get() ||
+      !resource_interface_->Reserve(size)) {
+    return;
+  }
+  size_ = size;
+}
+
 ScopedReservation::ScopedReservation(ScopedReservation&& other) noexcept
     : resource_interface_(other.resource_interface_),
       size_(std::exchange(other.size_, absl::nullopt)) {}
diff --git a/components/reporting/resources/resource_interface.h b/components/reporting/resources/resource_interface.h
index a3fb0fb..8f29c72 100644
--- a/components/reporting/resources/resource_interface.h
+++ b/components/reporting/resources/resource_interface.h
@@ -76,6 +76,10 @@
   ScopedReservation(
       uint64_t size,
       scoped_refptr<ResourceInterface> resource_interface) noexcept;
+  // New reservation on the same resource interface as |other_reservation|.
+  ScopedReservation(uint64_t size,
+                    const ScopedReservation& other_reservation) noexcept;
+  // Move constructor.
   ScopedReservation(ScopedReservation&& other) noexcept;
   ScopedReservation(const ScopedReservation& other) = delete;
   ScopedReservation& operator=(ScopedReservation&& other) = delete;
diff --git a/components/reporting/resources/resource_interface_unittest.cc b/components/reporting/resources/resource_interface_unittest.cc
index b77e4ec..3d627f1 100644
--- a/components/reporting/resources/resource_interface_unittest.cc
+++ b/components/reporting/resources/resource_interface_unittest.cc
@@ -188,6 +188,27 @@
               Eq(resource_interface()->GetTotal() - 1));
 }
 
+TEST_P(ResourceInterfaceTest, ScopedReservationRepeatingCopyHandOvers) {
+  uint64_t size = resource_interface()->GetTotal() / 2;
+  ScopedReservation scoped_reservation(size, resource_interface());
+  EXPECT_TRUE(scoped_reservation.reserved());
+
+  for (; size >= 2; size /= 2) {
+    ScopedReservation another_reservation(size / 2, scoped_reservation);
+    EXPECT_TRUE(another_reservation.reserved());
+    scoped_reservation.HandOver(another_reservation);
+  }
+  EXPECT_THAT(resource_interface()->GetUsed(),
+              Eq(resource_interface()->GetTotal() - 1));
+}
+
+TEST_P(ResourceInterfaceTest, ScopedReservationFailureToCopyFromEmpty) {
+  ScopedReservation scoped_reservation;
+  uint64_t size = resource_interface()->GetTotal() / 2;
+  ScopedReservation another_reservation(size, scoped_reservation);
+  EXPECT_FALSE(scoped_reservation.reserved());
+}
+
 TEST_P(ResourceInterfaceTest, ScopedReservationRepeatingHandOversToEmpty) {
   ScopedReservation scoped_reservation;
   EXPECT_FALSE(scoped_reservation.reserved());