EDK: Add HandleTable::AddHandleVector().

It'll replace AddDispatcherVector(), but there's a bunch of other work
needed before that can happen.

R=azani@chromium.org

Review URL: https://codereview.chromium.org/1949153002 .
diff --git a/mojo/edk/system/handle.h b/mojo/edk/system/handle.h
index 62218ce..df7fac2 100644
--- a/mojo/edk/system/handle.h
+++ b/mojo/edk/system/handle.h
@@ -5,6 +5,8 @@
 #ifndef MOJO_EDK_SYSTEM_HANDLE_H_
 #define MOJO_EDK_SYSTEM_HANDLE_H_
 
+#include <vector>
+
 #include "mojo/edk/util/ref_ptr.h"
 #include "mojo/public/c/system/handle.h"
 
@@ -42,6 +44,8 @@
   MojoHandleRights rights;
 };
 
+using HandleVector = std::vector<Handle>;
+
 }  // namespace system
 }  // namespace mojo
 
diff --git a/mojo/edk/system/handle_table.cc b/mojo/edk/system/handle_table.cc
index 90da427..7bff6f3 100644
--- a/mojo/edk/system/handle_table.cc
+++ b/mojo/edk/system/handle_table.cc
@@ -83,6 +83,33 @@
              : std::make_pair(MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID);
 }
 
+bool HandleTable::AddHandleVector(HandleVector* handles,
+                                  MojoHandle* handle_values) {
+  size_t max_message_num_handles = GetConfiguration().max_message_num_handles;
+
+  DCHECK(handles);
+  DCHECK_LE(handles->size(), max_message_num_handles);
+  DCHECK(handle_values);
+  DCHECK_LT(
+      static_cast<uint64_t>(max_handle_table_size_) + max_message_num_handles,
+      std::numeric_limits<size_t>::max())
+      << "Addition may overflow";
+
+  if (handle_to_entry_map_.size() + handles->size() > max_handle_table_size_)
+    return false;
+
+  for (size_t i = 0; i < handles->size(); i++) {
+    if (handles->at(i)) {
+      handle_values[i] = AddHandleNoSizeCheck(std::move(handles->at(i)));
+    } else {
+      LOG(WARNING) << "Invalid dispatcher at index " << i;
+      handle_values[i] = MOJO_HANDLE_INVALID;
+    }
+  }
+  return true;
+}
+
+// TODO(vtl): Delete this.
 bool HandleTable::AddDispatcherVector(const DispatcherVector& dispatchers,
                                       MojoHandle* handles) {
   size_t max_message_num_handles = GetConfiguration().max_message_num_handles;
diff --git a/mojo/edk/system/handle_table.h b/mojo/edk/system/handle_table.h
index 19b3aa5..4cdbd36 100644
--- a/mojo/edk/system/handle_table.h
+++ b/mojo/edk/system/handle_table.h
@@ -74,12 +74,15 @@
   std::pair<MojoHandle, MojoHandle> AddHandlePair(Handle&& handle0,
                                                   Handle&& handle1);
 
-  // Adds the given vector of dispatchers (of size at most
+  // Adds the given vector of handles (of size at most
   // |kMaxMessageNumHandles|). |handle_values| must point to an array of size at
-  // least |dispatchers.size()|. Unlike the other |AddDispatcher...()|
-  // functions, some of the dispatchers may be invalid (null). Returns true on
-  // success and false on failure (if the handle table is full), in which case
-  // it leaves |handle_values[...]| untouched (and all dispatchers unadded).
+  // least |handles->size()|. Unlike the other |AddHandle...()| functions, some
+  // of the handles may be invalid ("null"). Returns true on success in which
+  // case all the handles in |*handles| are moved from, and false on failure (if
+  // the handle table is full), in which case it leaves all |handles->at(...)||
+  // (and all the handles unadded) and |handle_values[...]| untouched.
+  bool AddHandleVector(HandleVector* handles, MojoHandle* handle_values);
+  // TODO(vtl): Delete this version (use |AddHandleVector()| instead).
   bool AddDispatcherVector(const DispatcherVector& dispatchers,
                            MojoHandle* handle_values);
 
diff --git a/mojo/edk/system/handle_table_unittest.cc b/mojo/edk/system/handle_table_unittest.cc
index a239962..33c983d 100644
--- a/mojo/edk/system/handle_table_unittest.cc
+++ b/mojo/edk/system/handle_table_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "mojo/edk/system/handle_table.h"
 
+#include <vector>
+
 #include "mojo/edk/system/dispatcher.h"
 #include "mojo/edk/system/handle.h"
 #include "mojo/edk/system/mock_simple_dispatcher.h"
@@ -175,6 +177,73 @@
   EXPECT_EQ(MOJO_RESULT_OK, d4->Close());
 }
 
+TEST(HandleTableTest, AddHandleVector) {
+  static constexpr size_t kNumHandles = 10u;
+
+  HandleTable ht(1000u);
+
+  HandleVector handles;
+  std::vector<RefPtr<Dispatcher>> dispatchers;
+  for (size_t i = 0u; i < kNumHandles; i++) {
+    dispatchers.push_back(MakeRefCounted<test::MockSimpleDispatcher>());
+    handles.push_back(
+        Handle(dispatchers.back().Clone(), MOJO_HANDLE_RIGHT_NONE));
+    ASSERT_TRUE(handles[i]) << i;
+  }
+
+  std::vector<MojoHandle> handle_values(kNumHandles, MOJO_HANDLE_INVALID);
+
+  ASSERT_TRUE(ht.AddHandleVector(&handles, handle_values.data()));
+
+  for (size_t i = 0u; i < kNumHandles; i++) {
+    ASSERT_NE(handle_values[i], MOJO_HANDLE_INVALID) << i;
+
+    RefPtr<Dispatcher> d;
+    ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(handle_values[i], &d))
+        << i;
+    ASSERT_EQ(dispatchers[i], d) << i;
+
+    EXPECT_EQ(MOJO_RESULT_OK, dispatchers[i]->Close()) << i;
+  }
+}
+
+TEST(HandleTableTest, AddHandleVectorTooMany) {
+  static constexpr size_t kHandleTableSize = 10u;
+  static constexpr size_t kNumHandles = kHandleTableSize + 1u;
+
+  HandleTable ht(kHandleTableSize);
+
+  HandleVector handles;
+  std::vector<RefPtr<Dispatcher>> dispatchers;
+  for (size_t i = 0u; i < kNumHandles; i++) {
+    dispatchers.push_back(MakeRefCounted<test::MockSimpleDispatcher>());
+    handles.push_back(
+        Handle(dispatchers.back().Clone(), MOJO_HANDLE_RIGHT_NONE));
+    ASSERT_TRUE(handles[i]) << i;
+  }
+
+  std::vector<MojoHandle> handle_values(kNumHandles, MOJO_HANDLE_INVALID);
+
+  EXPECT_FALSE(ht.AddHandleVector(&handles, handle_values.data()));
+
+  handles.pop_back();
+  handle_values.pop_back();
+
+  ASSERT_TRUE(ht.AddHandleVector(&handles, handle_values.data()));
+
+  for (size_t i = 0u; i < kNumHandles - 1u; i++) {
+    ASSERT_NE(handle_values[i], MOJO_HANDLE_INVALID) << i;
+
+    RefPtr<Dispatcher> d;
+    ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(handle_values[i], &d))
+        << i;
+    ASSERT_EQ(dispatchers[i], d) << i;
+  }
+
+  for (size_t i = 0u; i < kNumHandles; i++)
+    EXPECT_EQ(MOJO_RESULT_OK, dispatchers[i]->Close()) << i;
+}
+
 }  // namespace
 }  // namespace system
 }  // namespace mojo