Refactor container update by preferring the range insert.

The range operation is generally more efficient than inserting within a
loop, as it avoids having to do a capacity check each loop iteration,
instead pre-allocating the necessary block of memory all at once and
then doing an optimized batch insert.

Change-Id: I79c5db3075c7afe71e4484e20188307deeb60a4f
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/20080
Reviewed-by: Sylvain Defresne <sdefresne@chromium.org>
Reviewed-by: Jeffrey Yu <yuje@google.com>
Commit-Queue: Jeffrey Yu <yuje@google.com>
diff --git a/src/gn/operators.cc b/src/gn/operators.cc
index 7c04dd3..93cbe72 100644
--- a/src/gn/operators.cc
+++ b/src/gn/operators.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 #include <algorithm>
+#include <iterator>
 
 #include "base/strings/string_number_conversions.h"
 #include "gn/err.h"
@@ -375,9 +376,11 @@
   if (left.type() == Value::LIST && right.type() == Value::LIST) {
     // Since left was passed by copy, avoid realloc by destructively appending
     // to it and using that as the result.
-    for (Value& value : right.list_value())
-      left.list_value().push_back(std::move(value));
-    return left;  // FIXME(brettw) does this copy?
+    auto& right_list = right.list_value();
+    left.list_value().insert(left.list_value().end(),
+                             std::make_move_iterator(right_list.begin()),
+                             std::make_move_iterator(right_list.end()));
+    return left;
   }
 
   *err = MakeIncompatibleTypeError(op_node, left, right);