Add support for temporary spans in additional absl::c_* container algorithms.

Allow `absl::c_partial_sort`, `absl::c_lower_bound`, `absl::c_upper_bound`, `absl::c_equal_range`, `absl::c_sort_heap`, `absl::c_min_element`, and `absl::c_max_element` to accept rvalue spans while continuing to reject other temporary containers via `IsBorrowedRange`.

Renamed `IsPermissibleDestinationRange` to `IsBorrowedRange`.

PiperOrigin-RevId: 998254614
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h
index 5c2d376..1db7da7 100644
--- a/absl/algorithm/container.h
+++ b/absl/algorithm/container.h
@@ -209,29 +209,32 @@
 struct IsSpan<std::span<T, Extent>> : std::true_type {};
 #endif
 
-// Indicates whether the given type is safe to pass as a sink to a function such
-// as absl::c_fill(). Similar idea as std::ranges::borrowed_range.
+// Indicates whether the given type is a borrowed range, meaning it is safe to
+// return iterators from it even when passed as an rvalue (or use as a sink
+// for algorithms that mutate the container). Similar to
+// std::ranges::borrowed_range.
 //
 // We are deliberately conservative here and only support lvalues and spans for
 // now, in order to avoid divergence from C++17 or potentially unforeseen
 // consequences. If needed in the future, we can probably extend this to all
 // types that satisfy std::ranges::borrowed_range.
 template <typename C>
-using IsPermissibleDestinationRange =
-    std::conditional_t<std::is_lvalue_reference_v<C>, std::true_type,
-                       IsSpan<C>>;
+using IsBorrowedRange = std::conditional_t<std::is_lvalue_reference_v<C>,
+                                           std::true_type, IsSpan<C>>;
+
+template <typename C>
+using IsPermissibleDestinationRange = IsBorrowedRange<C>;
 
 template <typename C, typename OutputRange>
-using ResultOfRangeToRangeTransfer =
-    std::enable_if_t<container_algorithm_internal::HasBeginEnd<
-                         std::add_lvalue_reference_t<OutputRange>>::value &&
-                         !container_algorithm_internal::IsMultidimensionalArray<
-                             std::remove_reference_t<OutputRange>>::value &&
-                         !container_algorithm_internal::IsMultidimensionalArray<
-                             std::remove_reference_t<C>>::value &&
-                         container_algorithm_internal::
-                             IsPermissibleDestinationRange<OutputRange>::value,
-                     void>;
+using ResultOfRangeToRangeTransfer = std::enable_if_t<
+    container_algorithm_internal::HasBeginEnd<
+        std::add_lvalue_reference_t<OutputRange>>::value &&
+        !container_algorithm_internal::IsMultidimensionalArray<
+            std::remove_reference_t<OutputRange>>::value &&
+        !container_algorithm_internal::IsMultidimensionalArray<
+            std::remove_reference_t<C>>::value &&
+        container_algorithm_internal::IsBorrowedRange<OutputRange>::value,
+    void>;
 
 }  // namespace container_algorithm_internal
 
@@ -919,7 +922,7 @@
 // container with some value.
 template <typename C, typename T>
 constexpr std::enable_if_t<
-    container_algorithm_internal::IsPermissibleDestinationRange<C>::value, void>
+    container_algorithm_internal::IsBorrowedRange<C>::value, void>
 c_fill(C&& c, const T& value) {
   std::fill(container_algorithm_internal::c_begin(c),
             container_algorithm_internal::c_end(c), value);
@@ -931,7 +934,7 @@
 // the first N elements in a container with some value.
 template <typename C, typename Size, typename T>
 constexpr std::enable_if_t<
-    container_algorithm_internal::IsPermissibleDestinationRange<C>::value, void>
+    container_algorithm_internal::IsBorrowedRange<C>::value, void>
 c_fill_n(C&& c, Size n, const T& value) {
   std::fill_n(container_algorithm_internal::c_begin(c), n, value);
 }
@@ -1170,7 +1173,7 @@
 // to sort elements in ascending order of their values.
 template <typename C>
 constexpr std::enable_if_t<
-    container_algorithm_internal::IsPermissibleDestinationRange<C>::value, void>
+    container_algorithm_internal::IsBorrowedRange<C>::value, void>
 c_sort(C&& c) {
   std::sort(container_algorithm_internal::c_begin(c),
             container_algorithm_internal::c_end(c));
@@ -1180,7 +1183,7 @@
 // default `operator<`.
 template <typename C, typename LessThan>
 constexpr std::enable_if_t<
-    container_algorithm_internal::IsPermissibleDestinationRange<C>::value, void>
+    container_algorithm_internal::IsBorrowedRange<C>::value, void>
 c_sort(C&& c, LessThan&& comp) {
   std::sort(container_algorithm_internal::c_begin(c),
             container_algorithm_internal::c_end(c),
@@ -1193,8 +1196,7 @@
 // to sort elements in ascending order of their values, preserving the order
 // of equivalents.
 template <typename C>
-std::enable_if_t<
-    container_algorithm_internal::IsPermissibleDestinationRange<C>::value, void>
+std::enable_if_t<container_algorithm_internal::IsBorrowedRange<C>::value, void>
 c_stable_sort(C&& c) {
   std::stable_sort(container_algorithm_internal::c_begin(c),
                    container_algorithm_internal::c_end(c));
@@ -1203,8 +1205,7 @@
 // Overload of c_stable_sort() for performing a `comp` comparison other than the
 // default `operator<`.
 template <typename C, typename LessThan>
-std::enable_if_t<
-    container_algorithm_internal::IsPermissibleDestinationRange<C>::value, void>
+std::enable_if_t<container_algorithm_internal::IsBorrowedRange<C>::value, void>
 c_stable_sort(C&& c, LessThan&& comp) {
   std::stable_sort(container_algorithm_internal::c_begin(c),
                    container_algorithm_internal::c_end(c),
@@ -1236,8 +1237,11 @@
 // to rearrange elements within a container such that elements before `middle`
 // are sorted in ascending order.
 template <typename RandomAccessContainer>
-constexpr void c_partial_sort(
-    RandomAccessContainer& sequence,
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<RandomAccessContainer>::value,
+    void>
+c_partial_sort(
+    RandomAccessContainer&& sequence,
     container_algorithm_internal::ContainerIter<RandomAccessContainer> middle) {
   std::partial_sort(container_algorithm_internal::c_begin(sequence), middle,
                     container_algorithm_internal::c_end(sequence));
@@ -1246,8 +1250,11 @@
 // Overload of c_partial_sort() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename RandomAccessContainer, typename LessThan>
-constexpr void c_partial_sort(
-    RandomAccessContainer& sequence,
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<RandomAccessContainer>::value,
+    void>
+c_partial_sort(
+    RandomAccessContainer&& sequence,
     container_algorithm_internal::ContainerIter<RandomAccessContainer> middle,
     LessThan&& comp) {
   std::partial_sort(container_algorithm_internal::c_begin(sequence), middle,
@@ -1343,8 +1350,10 @@
 // to return an iterator pointing to the first element in a sorted container
 // which does not compare less than `value`.
 template <typename Sequence, typename T>
-constexpr container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
-    Sequence& sequence, const T& value) {
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<Sequence>::value,
+    container_algorithm_internal::ContainerIter<Sequence>>
+c_lower_bound(Sequence&& sequence, const T& value) {
   return std::lower_bound(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence), value);
 }
@@ -1352,8 +1361,10 @@
 // Overload of c_lower_bound() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename Sequence, typename T, typename LessThan>
-constexpr container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
-    Sequence& sequence, const T& value, LessThan&& comp) {
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<Sequence>::value,
+    container_algorithm_internal::ContainerIter<Sequence>>
+c_lower_bound(Sequence&& sequence, const T& value, LessThan&& comp) {
   return std::lower_bound(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence), value,
                           std::forward<LessThan>(comp));
@@ -1365,8 +1376,10 @@
 // to return an iterator pointing to the first element in a sorted container
 // which is greater than `value`.
 template <typename Sequence, typename T>
-constexpr container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
-    Sequence& sequence, const T& value) {
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<Sequence>::value,
+    container_algorithm_internal::ContainerIter<Sequence>>
+c_upper_bound(Sequence&& sequence, const T& value) {
   return std::upper_bound(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence), value);
 }
@@ -1374,8 +1387,10 @@
 // Overload of c_upper_bound() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename Sequence, typename T, typename LessThan>
-constexpr container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
-    Sequence& sequence, const T& value, LessThan&& comp) {
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<Sequence>::value,
+    container_algorithm_internal::ContainerIter<Sequence>>
+c_upper_bound(Sequence&& sequence, const T& value, LessThan&& comp) {
   return std::upper_bound(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence), value,
                           std::forward<LessThan>(comp));
@@ -1387,9 +1402,10 @@
 // to return an iterator pair pointing to the first and last elements in a
 // sorted container which compare equal to `value`.
 template <typename Sequence, typename T>
-constexpr container_algorithm_internal::ContainerIterPairType<Sequence,
-                                                              Sequence>
-c_equal_range(Sequence& sequence, const T& value) {
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<Sequence>::value,
+    container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>>
+c_equal_range(Sequence&& sequence, const T& value) {
   return std::equal_range(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence), value);
 }
@@ -1397,9 +1413,10 @@
 // Overload of c_equal_range() for performing a `comp` comparison other than
 // the default `operator<`.
 template <typename Sequence, typename T, typename LessThan>
-constexpr container_algorithm_internal::ContainerIterPairType<Sequence,
-                                                              Sequence>
-c_equal_range(Sequence& sequence, const T& value, LessThan&& comp) {
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<Sequence>::value,
+    container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>>
+c_equal_range(Sequence&& sequence, const T& value, LessThan&& comp) {
   return std::equal_range(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence), value,
                           std::forward<LessThan>(comp));
@@ -1726,7 +1743,10 @@
 // Container-based version of the <algorithm> `std::sort_heap()` function
 // to sort a heap into ascending order (after which it is no longer a heap).
 template <typename RandomAccessContainer>
-constexpr void c_sort_heap(RandomAccessContainer& sequence) {
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<RandomAccessContainer>::value,
+    void>
+c_sort_heap(RandomAccessContainer&& sequence) {
   std::sort_heap(container_algorithm_internal::c_begin(sequence),
                  container_algorithm_internal::c_end(sequence));
 }
@@ -1734,7 +1754,10 @@
 // Overload of c_sort_heap() for performing heap comparisons using a
 // `comp` other than `operator<`
 template <typename RandomAccessContainer, typename LessThan>
-constexpr void c_sort_heap(RandomAccessContainer& sequence, LessThan&& comp) {
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<RandomAccessContainer>::value,
+    void>
+c_sort_heap(RandomAccessContainer&& sequence, LessThan&& comp) {
   std::sort_heap(container_algorithm_internal::c_begin(sequence),
                  container_algorithm_internal::c_end(sequence),
                  std::forward<LessThan>(comp));
@@ -1791,8 +1814,10 @@
 // to return an iterator pointing to the element with the smallest value, using
 // `operator<` to make the comparisons.
 template <typename Sequence>
-constexpr container_algorithm_internal::ContainerIter<Sequence> c_min_element(
-    Sequence& sequence) {
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<Sequence>::value,
+    container_algorithm_internal::ContainerIter<Sequence>>
+c_min_element(Sequence&& sequence) {
   return std::min_element(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence));
 }
@@ -1800,8 +1825,10 @@
 // Overload of c_min_element() for performing a `comp` comparison other than
 // `operator<`.
 template <typename Sequence, typename LessThan>
-constexpr container_algorithm_internal::ContainerIter<Sequence> c_min_element(
-    Sequence& sequence, LessThan&& comp) {
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<Sequence>::value,
+    container_algorithm_internal::ContainerIter<Sequence>>
+c_min_element(Sequence&& sequence, LessThan&& comp) {
   return std::min_element(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence),
                           std::forward<LessThan>(comp));
@@ -1813,8 +1840,10 @@
 // to return an iterator pointing to the element with the largest value, using
 // `operator<` to make the comparisons.
 template <typename Sequence>
-constexpr container_algorithm_internal::ContainerIter<Sequence> c_max_element(
-    Sequence& sequence) {
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<Sequence>::value,
+    container_algorithm_internal::ContainerIter<Sequence>>
+c_max_element(Sequence&& sequence) {
   return std::max_element(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence));
 }
@@ -1822,8 +1851,10 @@
 // Overload of c_max_element() for performing a `comp` comparison other than
 // `operator<`.
 template <typename Sequence, typename LessThan>
-constexpr container_algorithm_internal::ContainerIter<Sequence> c_max_element(
-    Sequence& sequence, LessThan&& comp) {
+constexpr std::enable_if_t<
+    container_algorithm_internal::IsBorrowedRange<Sequence>::value,
+    container_algorithm_internal::ContainerIter<Sequence>>
+c_max_element(Sequence&& sequence, LessThan&& comp) {
   return std::max_element(container_algorithm_internal::c_begin(sequence),
                           container_algorithm_internal::c_end(sequence),
                           std::forward<LessThan>(comp));
diff --git a/absl/algorithm/container_test.cc b/absl/algorithm/container_test.cc
index 50a621e..dda791b 100644
--- a/absl/algorithm/container_test.cc
+++ b/absl/algorithm/container_test.cc
@@ -371,6 +371,12 @@
   EXPECT_EQ(3, *i);
 }
 
+TEST_F(NonMutatingTest, LowerBoundTemporarySpan) {
+  int* i = absl::c_lower_bound(absl::MakeSpan(vector_), 3);
+  EXPECT_EQ(2, std::distance(vector_.data(), i));
+  EXPECT_EQ(3, *i);
+}
+
 TEST_F(NonMutatingTest, LowerBoundWithPredicate) {
   std::vector<int> v(vector_);
   std::sort(v.begin(), v.end(), std::greater<int>());
@@ -379,6 +385,14 @@
   EXPECT_EQ(3, *i);
 }
 
+TEST_F(NonMutatingTest, LowerBoundTemporarySpanWithPredicate) {
+  std::vector<int> v(vector_);
+  std::sort(v.begin(), v.end(), std::greater<int>());
+  int* i = absl::c_lower_bound(absl::MakeSpan(v), 3, std::greater<int>());
+  EXPECT_TRUE(i == v.data());
+  EXPECT_EQ(3, *i);
+}
+
 TEST_F(NonMutatingTest, UpperBound) {
   std::list<int>::iterator i = absl::c_upper_bound(sequence_, 1);
   ASSERT_TRUE(i != sequence_.end());
@@ -386,6 +400,12 @@
   EXPECT_EQ(2, *i);
 }
 
+TEST_F(NonMutatingTest, UpperBoundTemporarySpan) {
+  int* i = absl::c_upper_bound(absl::MakeSpan(vector_), 1);
+  EXPECT_EQ(1, std::distance(vector_.data(), i));
+  EXPECT_EQ(2, *i);
+}
+
 TEST_F(NonMutatingTest, UpperBoundWithPredicate) {
   std::vector<int> v(vector_);
   std::sort(v.begin(), v.end(), std::greater<int>());
@@ -394,6 +414,14 @@
   EXPECT_TRUE(i == v.end());
 }
 
+TEST_F(NonMutatingTest, UpperBoundTemporarySpanWithPredicate) {
+  std::vector<int> v(vector_);
+  std::sort(v.begin(), v.end(), std::greater<int>());
+  int* i = absl::c_upper_bound(absl::MakeSpan(v), 1, std::greater<int>());
+  EXPECT_EQ(3, i - v.data());
+  EXPECT_TRUE(i == v.data() + v.size());
+}
+
 TEST_F(NonMutatingTest, EqualRange) {
   std::pair<std::list<int>::iterator, std::list<int>::iterator> p =
       absl::c_equal_range(sequence_, 2);
@@ -401,6 +429,12 @@
   EXPECT_EQ(2, std::distance(sequence_.begin(), p.second));
 }
 
+TEST_F(NonMutatingTest, EqualRangeTemporarySpan) {
+  std::pair<int*, int*> p = absl::c_equal_range(absl::MakeSpan(vector_), 2);
+  EXPECT_EQ(1, std::distance(vector_.data(), p.first));
+  EXPECT_EQ(2, std::distance(vector_.data(), p.second));
+}
+
 TEST_F(NonMutatingTest, EqualRangeArray) {
   auto p = absl::c_equal_range(array_, 2);
   EXPECT_EQ(1, std::distance(std::begin(array_), p.first));
@@ -416,6 +450,15 @@
   EXPECT_EQ(2, std::distance(v.begin(), p.second));
 }
 
+TEST_F(NonMutatingTest, EqualRangeTemporarySpanWithPredicate) {
+  std::vector<int> v(vector_);
+  std::sort(v.begin(), v.end(), std::greater<int>());
+  std::pair<int*, int*> p =
+      absl::c_equal_range(absl::MakeSpan(v), 2, std::greater<int>());
+  EXPECT_EQ(1, std::distance(v.data(), p.first));
+  EXPECT_EQ(2, std::distance(v.data(), p.second));
+}
+
 TEST_F(NonMutatingTest, BinarySearch) {
   EXPECT_TRUE(absl::c_binary_search(vector_, 2));
   EXPECT_TRUE(absl::c_binary_search(std::vector<int>(vector_), 2));
@@ -435,6 +478,12 @@
   EXPECT_EQ(*i, 1);
 }
 
+TEST_F(NonMutatingTest, MinElementTemporarySpan) {
+  int* i = absl::c_min_element(absl::MakeSpan(vector_));
+  ASSERT_TRUE(i != vector_.data() + vector_.size());
+  EXPECT_EQ(*i, 1);
+}
+
 TEST_F(NonMutatingTest, MinElementWithPredicate) {
   std::list<int>::iterator i =
       absl::c_min_element(sequence_, std::greater<int>());
@@ -442,12 +491,24 @@
   EXPECT_EQ(*i, 3);
 }
 
+TEST_F(NonMutatingTest, MinElementTemporarySpanWithPredicate) {
+  int* i = absl::c_min_element(absl::MakeSpan(vector_), std::greater<int>());
+  ASSERT_TRUE(i != vector_.data() + vector_.size());
+  EXPECT_EQ(*i, 3);
+}
+
 TEST_F(NonMutatingTest, MaxElement) {
   std::list<int>::iterator i = absl::c_max_element(sequence_);
   ASSERT_TRUE(i != sequence_.end());
   EXPECT_EQ(*i, 3);
 }
 
+TEST_F(NonMutatingTest, MaxElementTemporarySpan) {
+  int* i = absl::c_max_element(absl::MakeSpan(vector_));
+  ASSERT_TRUE(i != vector_.data() + vector_.size());
+  EXPECT_EQ(*i, 3);
+}
+
 TEST_F(NonMutatingTest, MaxElementWithPredicate) {
   std::list<int>::iterator i =
       absl::c_max_element(sequence_, std::greater<int>());
@@ -455,6 +516,12 @@
   EXPECT_EQ(*i, 1);
 }
 
+TEST_F(NonMutatingTest, MaxElementTemporarySpanWithPredicate) {
+  int* i = absl::c_max_element(absl::MakeSpan(vector_), std::greater<int>());
+  ASSERT_TRUE(i != vector_.data() + vector_.size());
+  EXPECT_EQ(*i, 1);
+}
+
 TEST_F(NonMutatingTest, LexicographicalCompare) {
   EXPECT_FALSE(absl::c_lexicographical_compare(sequence_, sequence_));
 
@@ -1533,6 +1600,15 @@
   EXPECT_THAT(absl::MakeSpan(sequence.data(), 2), ElementsAre(42, 5));
 }
 
+TEST(MutatingTest, PartialSortTemporarySpan) {
+  std::vector<int> sequence{5, 3, 42, 0};
+  absl::c_partial_sort(absl::MakeSpan(sequence), sequence.data() + 2);
+  EXPECT_THAT(absl::MakeSpan(sequence).first(2), ElementsAre(0, 3));
+  absl::c_partial_sort(absl::MakeSpan(sequence), sequence.data() + 2,
+                       std::greater<int>());
+  EXPECT_THAT(absl::MakeSpan(sequence).first(2), ElementsAre(42, 5));
+}
+
 TEST(MutatingTest, PartialSortCopy) {
   const std::vector<int> initial = {5, 3, 42, 0};
   std::vector<int> actual(2);
@@ -1664,6 +1740,23 @@
   EXPECT_FALSE(absl::c_is_heap(heap, greater()));
 }
 
+TEST(HeapOperationsTest, SortHeapTemporarySpan) {
+  std::vector<int> heap = {1, 2, 3, 4};
+  absl::c_make_heap(heap);
+  absl::c_sort_heap(absl::MakeSpan(heap));
+  EXPECT_THAT(heap, ElementsAre(1, 2, 3, 4));
+  EXPECT_FALSE(absl::c_is_heap(heap));
+}
+
+TEST(HeapOperationsTest, SortHeapTemporarySpanWithComparator) {
+  using greater = std::greater<int>;
+  std::vector<int> heap = {4, 3, 2, 1};
+  absl::c_make_heap(heap, greater());
+  absl::c_sort_heap(absl::MakeSpan(heap), greater());
+  EXPECT_THAT(heap, ElementsAre(4, 3, 2, 1));
+  EXPECT_FALSE(absl::c_is_heap(heap, greater()));
+}
+
 TEST(MutatingTest, PermutationOperations) {
   std::vector<int> initial = {1, 2, 3, 4};
   std::vector<int> permuted = initial;
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc
index baed443..e60b237 100644
--- a/absl/container/internal/raw_hash_set.cc
+++ b/absl/container/internal/raw_hash_set.cc
@@ -852,7 +852,7 @@
   ABSL_SWISSTABLE_ASSERT(c.capacity() > 0);
   if (policy.destroy_slot != nullptr) {
     if (c.is_small()) {
-      if (!c.empty()) {
+      if (!c.empty_when_small()) {
         static_assert(kMaxSmallCapacity == 1);
         policy.destroy_slot(&c, c.single_non_soo_slot());
       }
@@ -948,7 +948,7 @@
   if (c.is_small()) {
     // In the small case, we keep the backing array allocation because the
     // memory overhead is small compared to the potential benefits of reuse.
-    if (!c.empty()) {
+    if (!c.empty_when_small()) {
       if (destroy_slot != nullptr) {
         destroy_slot(&c, SingleSlotAddress<kSooEnabled>(c));
       }
@@ -2039,7 +2039,7 @@
                                void* hasher, HashForKeyFn get_hash) {
   ABSL_SWISSTABLE_ASSERT(common.is_small());
   ABSL_SWISSTABLE_ASSERT(!policy.soo_enabled);
-  const bool is_empty = common.empty();
+  const bool is_empty = common.empty_when_small();
   if (common.capacity() == 1 && is_empty) {
     IncrementSmallSizeNonSoo(common, policy);
     // Compute before `RecordInsertMissCold` to avoid reloading `control_`.
@@ -2052,7 +2052,7 @@
     return res;
   }
 
-  const size_t size = common.size();
+  const size_t size = is_empty ? 0 : 1;
   const bool has_infoz =
       is_empty ? (policy.is_hashtablez_enabled && ShouldSampleNextTable())
                : common.has_infoz();
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index ce8a1e4..08cc0d1 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -853,6 +853,12 @@
   void decrement_size() { data_ -= kSizeOneNoMetadata; }
   // Returns true if the table is empty.
   bool empty() const { return data_ < kSizeOneNoMetadata; }
+  // Returns true if a small table (capacity <= 1) is empty.
+  bool empty_when_small() const {
+    ABSL_SWISSTABLE_ASSERT(is_small());
+    ABSL_SWISSTABLE_ASSERT(size() <= 1);
+    return (data_ & kSizeOneNoMetadata) == 0;
+  }
 
   // Returns true if an empty SOO table has already queried should_sample_soo().
   bool soo_has_tried_sampling() const {
@@ -1419,6 +1425,7 @@
     inline_data_.decrement_size();
   }
   bool empty() const { return inline_data_.empty(); }
+  bool empty_when_small() const { return inline_data_.empty_when_small(); }
   void set_soo_has_tried_sampling() {
     inline_data_.set_soo_has_tried_sampling();
   }
@@ -2515,18 +2522,15 @@
     return SizeToCapacity(MaxValidSize());
   }
 
-  // Whether `size` fits in the SOO capacity of this table.
-  bool fits_in_soo(size_t size) const {
-    return SooEnabled() && size <= SooCapacity();
-  }
   // Whether this table is in SOO mode or non-SOO mode.
   bool is_soo() const {
-    HashtableCapacity cap = maybe_invalid_capacity();
-    return cap.IsValid() && fits_in_soo(cap.capacity());
+    static_assert(SooCapacity() == kMaxSmallCapacity);
+    return SooEnabled() && maybe_invalid_capacity().is_small();
   }
-  bool is_full_soo() const { return is_soo() && !empty(); }
+  bool is_full_soo() const { return is_soo() && !empty_when_small(); }
 
   bool is_small() const { return common().is_small(); }
+  bool empty_when_small() const { return common().empty_when_small(); }
 
   // Give an early error when key_type is not hashable/eq.
   auto KeyTypeCanBeHashed(const Hash& h, const key_type& k) -> decltype(h(k));
@@ -3351,7 +3355,7 @@
     };
 
     if (src.is_small()) {
-      if (src.empty()) return;
+      if (src.empty_when_small()) return;
       if (insert_slot(src.single_slot()))
         src.erase_meta_only_small();
       return;
@@ -3613,7 +3617,9 @@
   // SOO functionality.
   template <class K>
   ABSL_ATTRIBUTE_ALWAYS_INLINE iterator find_small(const K& key) {
-    return empty() || !equal_to(key, single_slot()) ? end() : single_iterator();
+    return empty_when_small() || !equal_to(key, single_slot())
+               ? end()
+               : single_iterator();
   }
 
   template <class K>
@@ -3687,8 +3693,8 @@
         kIsDefaultAlloc && BackingArrayAlignment(alignof(slot_type)) ==
                                kStandardBackingArrayAlignment;
     if constexpr (SooEnabled()) {
-      if (is_small() &&
-          (PolicyTraits::template destroy_is_trivial<Alloc>() || empty())) {
+      if (is_small() && (PolicyTraits::template destroy_is_trivial<Alloc>() ||
+                         empty_when_small())) {
         return;
       }
     } else {
@@ -3850,7 +3856,7 @@
   find_or_prepare_insert_soo(const K& key) {
     bool force_sampling;
     slot_type* slot = single_slot();
-    if (empty()) {
+    if (empty_when_small()) {
       if (!should_sample_soo()) {
         common().set_full_soo();
         return {slot, true};
@@ -3880,7 +3886,7 @@
     if constexpr (SooEnabled()) {
       return find_or_prepare_insert_soo(key);
     }
-    if (!empty()) {
+    if (!empty_when_small()) {
       if (equal_to(key, single_slot())) {
         return {single_slot(), false};
       }