A new user interface for you! Read more...

File 04-basevalue.patch of Package chromium

From e169e6c645c6c6f3175b052ed32bc0818bd637ee Mon Sep 17 00:00:00 2001
From: David 'Digit' Turner <digit@google.com>
Date: Thu, 28 Mar 2019 22:06:29 +0000
Subject: [PATCH] base: Add Value::Set<Type>Key() methods
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This CL adds convenience methods to set dictionary
keys to typed values. This is much more efficient than
calling SetKey() because it avoids the caller creating
and destroying a temporary Value instance that is later
moved into a heap allocated instance.

+ Update base/ sources that use SetBoolean(), SetInteger(),
  SetDouble() and SetString() to the new equivalent
  functions.

BUG=646113
R=dcheng@chromium.org,jdoerrie@chromium.org,sdefresne@chromium.org,hidehiko@chromium.org

Change-Id: I39e472bec36eb2018b5af0a083b3d1e3622eaad1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1530911
Commit-Queue: David Turner <digit@chromium.org>
Reviewed-by: oysteine <oysteine@chromium.org>
Reviewed-by: Mark Pearson <mpearson@chromium.org>
Reviewed-by: François Doray <fdoray@chromium.org>
Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#645529}
---
 base/json/json_perftest.cc                 |   8 +-
 base/json/json_writer_unittest.cc          |  14 +-
 base/metrics/histogram.cc                  |  12 +-
 base/metrics/histogram_base.cc             |  10 +-
 base/process/process_metrics.cc            |   2 +-
 base/process/process_metrics_linux.cc      |  42 +++---
 base/task/task_scheduler/task_tracker.cc   |   8 +-
 base/test/gtest_util.cc                    |   8 +-
 base/test/launcher/test_launcher_tracer.cc |   6 +-
 base/test/launcher/test_results_tracker.cc |  30 ++---
 base/trace_event/traced_value.cc           |  20 ++-
 base/values.cc                             |  38 +++++-
 base/values.h                              |  19 +++
 base/values_unittest.cc                    | 144 +++++++++++++++++----
 14 files changed, 250 insertions(+), 111 deletions(-)

Index: chromium-74.0.3729.108/base/json/json_perftest.cc
===================================================================
--- chromium-74.0.3729.108.orig/base/json/json_perftest.cc
+++ chromium-74.0.3729.108/base/json/json_perftest.cc
@@ -18,10 +18,10 @@ namespace {
 // list.
 std::unique_ptr<DictionaryValue> GenerateDict() {
   auto root = std::make_unique<DictionaryValue>();
-  root->SetDouble("Double", 3.141);
-  root->SetBoolean("Bool", true);
-  root->SetInteger("Int", 42);
-  root->SetString("String", "Foo");
+  root->SetDoubleKey("Double", 3.141);
+  root->SetBoolKey("Bool", true);
+  root->SetIntKey("Int", 42);
+  root->SetStringKey("String", "Foo");
 
   auto list = std::make_unique<ListValue>();
   list->Set(0, std::make_unique<Value>(2.718));
Index: chromium-74.0.3729.108/base/json/json_writer_unittest.cc
===================================================================
--- chromium-74.0.3729.108.orig/base/json/json_writer_unittest.cc
+++ chromium-74.0.3729.108/base/json/json_writer_unittest.cc
@@ -59,7 +59,7 @@ TEST(JSONWriterTest, NestedTypes) {
   DictionaryValue root_dict;
   std::unique_ptr<ListValue> list(new ListValue());
   std::unique_ptr<DictionaryValue> inner_dict(new DictionaryValue());
-  inner_dict->SetInteger("inner int", 10);
+  inner_dict->SetIntKey("inner int", 10);
   list->Append(std::move(inner_dict));
   list->Append(std::make_unique<ListValue>());
   list->AppendBoolean(true);
@@ -91,17 +91,17 @@ TEST(JSONWriterTest, KeysWithPeriods) {
   std::string output_js;
 
   DictionaryValue period_dict;
-  period_dict.SetKey("a.b", base::Value(3));
-  period_dict.SetKey("c", base::Value(2));
+  period_dict.SetIntKey("a.b", 3);
+  period_dict.SetIntKey("c", 2);
   std::unique_ptr<DictionaryValue> period_dict2(new DictionaryValue());
-  period_dict2->SetKey("g.h.i.j", base::Value(1));
+  period_dict2->SetIntKey("g.h.i.j", 1);
   period_dict.SetWithoutPathExpansion("d.e.f", std::move(period_dict2));
   EXPECT_TRUE(JSONWriter::Write(period_dict, &output_js));
   EXPECT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js);
 
   DictionaryValue period_dict3;
   period_dict3.SetInteger("a.b", 2);
-  period_dict3.SetKey("a.b", base::Value(1));
+  period_dict3.SetIntKey("a.b", 1);
   EXPECT_TRUE(JSONWriter::Write(period_dict3, &output_js));
   EXPECT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js);
 }
@@ -130,9 +130,9 @@ TEST(JSONWriterTest, BinaryValues) {
 
   DictionaryValue binary_dict;
   binary_dict.Set("a", Value::CreateWithCopiedBuffer("asdf", 4));
-  binary_dict.SetInteger("b", 5);
+  binary_dict.SetIntKey("b", 5);
   binary_dict.Set("c", Value::CreateWithCopiedBuffer("asdf", 4));
-  binary_dict.SetInteger("d", 2);
+  binary_dict.SetIntKey("d", 2);
   binary_dict.Set("e", Value::CreateWithCopiedBuffer("asdf", 4));
   EXPECT_FALSE(JSONWriter::Write(binary_dict, &output_js));
   EXPECT_TRUE(JSONWriter::WriteWithOptions(
Index: chromium-74.0.3729.108/base/metrics/histogram.cc
===================================================================
--- chromium-74.0.3729.108.orig/base/metrics/histogram.cc
+++ chromium-74.0.3729.108/base/metrics/histogram.cc
@@ -810,9 +810,9 @@ void Histogram::WriteAsciiBucketContext(
 
 void Histogram::GetParameters(DictionaryValue* params) const {
   params->SetString("type", HistogramTypeToString(GetHistogramType()));
-  params->SetInteger("min", declared_min());
-  params->SetInteger("max", declared_max());
-  params->SetInteger("bucket_count", static_cast<int>(bucket_count()));
+  params->SetIntKey("min", declared_min());
+  params->SetIntKey("max", declared_max());
+  params->SetIntKey("bucket_count", static_cast<int>(bucket_count()));
 }
 
 void Histogram::GetCountAndBucketData(Count* count,
@@ -826,10 +826,10 @@ void Histogram::GetCountAndBucketData(Co
     Sample count_at_index = snapshot->GetCountAtIndex(i);
     if (count_at_index > 0) {
       std::unique_ptr<DictionaryValue> bucket_value(new DictionaryValue());
-      bucket_value->SetInteger("low", ranges(i));
+      bucket_value->SetIntKey("low", ranges(i));
       if (i != bucket_count() - 1)
-        bucket_value->SetInteger("high", ranges(i + 1));
-      bucket_value->SetInteger("count", count_at_index);
+        bucket_value->SetIntKey("high", ranges(i + 1));
+      bucket_value->SetIntKey("count", count_at_index);
       buckets->Set(index, std::move(bucket_value));
       ++index;
     }
Index: chromium-74.0.3729.108/base/metrics/histogram_base.cc
===================================================================
--- chromium-74.0.3729.108.orig/base/metrics/histogram_base.cc
+++ chromium-74.0.3729.108/base/metrics/histogram_base.cc
@@ -152,14 +152,14 @@ void HistogramBase::WriteJSON(std::strin
 
   JSONStringValueSerializer serializer(output);
   DictionaryValue root;
-  root.SetString("name", histogram_name());
-  root.SetInteger("count", count);
-  root.SetDouble("sum", static_cast<double>(sum));
-  root.SetInteger("flags", flags());
+  root.SetStringKey("name", histogram_name());
+  root.SetIntKey("count", count);
+  root.SetDoubleKey("sum", static_cast<double>(sum));
+  root.SetIntKey("flags", flags());
   root.Set("params", std::move(parameters));
   if (verbosity_level != JSON_VERBOSITY_LEVEL_OMIT_BUCKETS)
     root.Set("buckets", std::move(buckets));
-  root.SetInteger("pid", GetUniqueIdForProcess());
+  root.SetIntKey("pid", GetUniqueIdForProcess());
   serializer.Serialize(root);
 }
 
Index: chromium-74.0.3729.108/base/process/process_metrics.cc
===================================================================
--- chromium-74.0.3729.108.orig/base/process/process_metrics.cc
+++ chromium-74.0.3729.108/base/process/process_metrics.cc
@@ -74,7 +74,7 @@ SystemMetrics SystemMetrics::Sample() {
 std::unique_ptr<Value> SystemMetrics::ToValue() const {
   std::unique_ptr<DictionaryValue> res(new DictionaryValue());
 
-  res->SetInteger("committed_memory", static_cast<int>(committed_memory_));
+  res->SetIntKey("committed_memory", static_cast<int>(committed_memory_));
 #if defined(OS_LINUX) || defined(OS_ANDROID)
   std::unique_ptr<DictionaryValue> meminfo = memory_info_.ToValue();
   std::unique_ptr<DictionaryValue> vmstat = vmstat_info_.ToValue();
Index: chromium-74.0.3729.108/base/process/process_metrics_linux.cc
===================================================================
--- chromium-74.0.3729.108.orig/base/process/process_metrics_linux.cc
+++ chromium-74.0.3729.108/base/process/process_metrics_linux.cc
@@ -470,25 +470,25 @@ const size_t kDiskWeightedIOTime = 13;
 
 std::unique_ptr<DictionaryValue> SystemMemoryInfoKB::ToValue() const {
   auto res = std::make_unique<DictionaryValue>();
-  res->SetInteger("total", total);
-  res->SetInteger("free", free);
-  res->SetInteger("available", available);
-  res->SetInteger("buffers", buffers);
-  res->SetInteger("cached", cached);
-  res->SetInteger("active_anon", active_anon);
-  res->SetInteger("inactive_anon", inactive_anon);
-  res->SetInteger("active_file", active_file);
-  res->SetInteger("inactive_file", inactive_file);
-  res->SetInteger("swap_total", swap_total);
-  res->SetInteger("swap_free", swap_free);
-  res->SetInteger("swap_used", swap_total - swap_free);
-  res->SetInteger("dirty", dirty);
-  res->SetInteger("reclaimable", reclaimable);
+  res->SetIntKey("total", total);
+  res->SetIntKey("free", free);
+  res->SetIntKey("available", available);
+  res->SetIntKey("buffers", buffers);
+  res->SetIntKey("cached", cached);
+  res->SetIntKey("active_anon", active_anon);
+  res->SetIntKey("inactive_anon", inactive_anon);
+  res->SetIntKey("active_file", active_file);
+  res->SetIntKey("inactive_file", inactive_file);
+  res->SetIntKey("swap_total", swap_total);
+  res->SetIntKey("swap_free", swap_free);
+  res->SetIntKey("swap_used", swap_total - swap_free);
+  res->SetIntKey("dirty", dirty);
+  res->SetIntKey("reclaimable", reclaimable);
 #ifdef OS_CHROMEOS
-  res->SetInteger("shmem", shmem);
-  res->SetInteger("slab", slab);
-  res->SetInteger("gem_objects", gem_objects);
-  res->SetInteger("gem_size", gem_size);
+  res->SetIntKey("shmem", shmem);
+  res->SetIntKey("slab", slab);
+  res->SetIntKey("gem_objects", gem_objects);
+  res->SetIntKey("gem_size", gem_size);
 #endif
 
   return res;
@@ -635,9 +635,9 @@ bool GetSystemMemoryInfo(SystemMemoryInf
 
 std::unique_ptr<DictionaryValue> VmStatInfo::ToValue() const {
   auto res = std::make_unique<DictionaryValue>();
-  res->SetInteger("pswpin", pswpin);
-  res->SetInteger("pswpout", pswpout);
-  res->SetInteger("pgmajfault", pgmajfault);
+  res->SetIntKey("pswpin", pswpin);
+  res->SetIntKey("pswpout", pswpout);
+  res->SetIntKey("pgmajfault", pgmajfault);
   return res;
 }
 
Index: chromium-74.0.3729.108/base/task/task_scheduler/task_tracker.cc
===================================================================
--- chromium-74.0.3729.108.orig/base/task/task_scheduler/task_tracker.cc
+++ chromium-74.0.3729.108/base/task/task_scheduler/task_tracker.cc
@@ -61,11 +61,11 @@ class TaskTracingInfo : public trace_eve
 void TaskTracingInfo::AppendAsTraceFormat(std::string* out) const {
   DictionaryValue dict;
 
-  dict.SetString("task_priority",
-                 base::TaskPriorityToString(task_traits_.priority()));
-  dict.SetString("execution_mode", execution_mode_);
+  dict.SetStringKey("task_priority",
+                    base::TaskPriorityToString(task_traits_.priority()));
+  dict.SetStringKey("execution_mode", execution_mode_);
   if (execution_mode_ != kParallelExecutionMode)
-    dict.SetInteger("sequence_token", sequence_token_.ToInternalValue());
+    dict.SetIntKey("sequence_token", sequence_token_.ToInternalValue());
 
   std::string tmp;
   JSONWriter::Write(dict, &tmp);
Index: chromium-74.0.3729.108/base/test/gtest_util.cc
===================================================================
--- chromium-74.0.3729.108.orig/base/test/gtest_util.cc
+++ chromium-74.0.3729.108/base/test/gtest_util.cc
@@ -56,10 +56,10 @@ bool WriteCompiledInTestsToFile(const Fi
   ListValue root;
   for (const auto& i : tests) {
     std::unique_ptr<DictionaryValue> test_info(new DictionaryValue);
-    test_info->SetString("test_case_name", i.test_case_name);
-    test_info->SetString("test_name", i.test_name);
-    test_info->SetString("file", i.file);
-    test_info->SetInteger("line", i.line);
+    test_info->SetStringKey("test_case_name", i.test_case_name);
+    test_info->SetStringKey("test_name", i.test_name);
+    test_info->SetStringKey("file", i.file);
+    test_info->SetIntKey("line", i.line);
     root.Append(std::move(test_info));
   }
 
Index: chromium-74.0.3729.108/base/test/launcher/test_launcher_tracer.cc
===================================================================
--- chromium-74.0.3729.108.orig/base/test/launcher/test_launcher_tracer.cc
+++ chromium-74.0.3729.108/base/test/launcher/test_launcher_tracer.cc
@@ -37,11 +37,11 @@ bool TestLauncherTracer::Dump(const File
     json_event->SetString("ph", "X");
     json_event->SetInteger(
         "ts", (event.timestamp - trace_start_time_).InMicroseconds());
-    json_event->SetInteger("dur", event.duration.InMicroseconds());
-    json_event->SetInteger("tid", event.thread_id);
+    json_event->SetIntKey("dur", event.duration.InMicroseconds());
+    json_event->SetIntKey("tid", event.thread_id);
 
     // Add fake values required by the trace viewer.
-    json_event->SetInteger("pid", 0);
+    json_event->SetIntKey("pid", 0);
 
     json_events->Append(std::move(json_event));
   }
Index: chromium-74.0.3729.108/base/test/launcher/test_results_tracker.cc
===================================================================
--- chromium-74.0.3729.108.orig/base/test/launcher/test_results_tracker.cc
+++ chromium-74.0.3729.108/base/test/launcher/test_results_tracker.cc
@@ -404,7 +404,7 @@ bool TestResultsTracker::SaveSummaryAsJS
 
         std::unique_ptr<DictionaryValue> test_result_value(new DictionaryValue);
 
-        test_result_value->SetString("status", test_result.StatusAsString());
+        test_result_value->SetStringKey("status", test_result.StatusAsString());
         test_result_value->SetInteger(
             "elapsed_time_ms",
             static_cast<int>(test_result.elapsed_time.InMilliseconds()));
@@ -422,7 +422,7 @@ bool TestResultsTracker::SaveSummaryAsJS
 
         // TODO(phajdan.jr): Fix typo in JSON key (losless -> lossless)
         // making sure not to break any consumers of this data.
-        test_result_value->SetBoolean("losless_snippet", lossless_snippet);
+        test_result_value->SetBoolKey("losless_snippet", lossless_snippet);
 
         // Also include the raw version (base64-encoded so that it can be safely
         // JSON-serialized - there are no guarantees about character encoding
@@ -430,43 +430,43 @@ bool TestResultsTracker::SaveSummaryAsJS
         // debugging a test failure related to character encoding.
         std::string base64_output_snippet;
         Base64Encode(test_result.output_snippet, &base64_output_snippet);
-        test_result_value->SetString("output_snippet_base64",
-                                     base64_output_snippet);
+        test_result_value->SetStringKey("output_snippet_base64",
+                                        base64_output_snippet);
 
         std::unique_ptr<ListValue> test_result_parts(new ListValue);
         for (const TestResultPart& result_part :
              test_result.test_result_parts) {
           std::unique_ptr<DictionaryValue> result_part_value(
               new DictionaryValue);
-          result_part_value->SetString("type", result_part.TypeAsString());
-          result_part_value->SetString("file", result_part.file_name);
-          result_part_value->SetInteger("line", result_part.line_number);
+          result_part_value->SetStringKey("type", result_part.TypeAsString());
+          result_part_value->SetStringKey("file", result_part.file_name);
+          result_part_value->SetIntKey("line", result_part.line_number);
 
           bool lossless_summary = IsStringUTF8(result_part.summary);
           if (lossless_summary) {
-            result_part_value->SetString("summary", result_part.summary);
+            result_part_value->SetStringKey("summary", result_part.summary);
           } else {
             result_part_value->SetString(
                 "summary", "<non-UTF-8 snippet, see summary_base64>");
           }
-          result_part_value->SetBoolean("lossless_summary", lossless_summary);
+          result_part_value->SetBoolKey("lossless_summary", lossless_summary);
 
           std::string encoded_summary;
           Base64Encode(result_part.summary, &encoded_summary);
-          result_part_value->SetString("summary_base64", encoded_summary);
+          result_part_value->SetStringKey("summary_base64", encoded_summary);
 
           bool lossless_message = IsStringUTF8(result_part.message);
           if (lossless_message) {
-            result_part_value->SetString("message", result_part.message);
+            result_part_value->SetStringKey("message", result_part.message);
           } else {
             result_part_value->SetString(
                 "message", "<non-UTF-8 snippet, see message_base64>");
           }
-          result_part_value->SetBoolean("lossless_message", lossless_message);
+          result_part_value->SetBoolKey("lossless_message", lossless_message);
 
           std::string encoded_message;
           Base64Encode(result_part.message, &encoded_message);
-          result_part_value->SetString("message_base64", encoded_message);
+          result_part_value->SetStringKey("message_base64", encoded_message);
 
           test_result_parts->Append(std::move(result_part_value));
         }
@@ -487,8 +487,8 @@ bool TestResultsTracker::SaveSummaryAsJS
     std::string test_name = item.first;
     CodeLocation location = item.second;
     std::unique_ptr<DictionaryValue> location_value(new DictionaryValue);
-    location_value->SetString("file", location.file);
-    location_value->SetInteger("line", location.line);
+    location_value->SetStringKey("file", location.file);
+    location_value->SetIntKey("line", location.line);
     test_locations->SetWithoutPathExpansion(test_name,
                                             std::move(location_value));
   }
Index: chromium-74.0.3729.108/base/trace_event/traced_value.cc
===================================================================
--- chromium-74.0.3729.108.orig/base/trace_event/traced_value.cc
+++ chromium-74.0.3729.108/base/trace_event/traced_value.cc
@@ -380,44 +380,40 @@ class PickleWriter final : public Traced
         case kTypeBool: {
           bool value;
           CHECK(it.ReadBool(&value));
-          base::Value new_bool(value);
           if (cur_dict) {
-            cur_dict->SetKey(ReadKeyName(it), std::move(new_bool));
+            cur_dict->SetBoolKey(ReadKeyName(it), value);
           } else {
-            cur_list->GetList().push_back(std::move(new_bool));
+            cur_list->GetList().emplace_back(value);
           }
         } break;
 
         case kTypeInt: {
           int value;
           CHECK(it.ReadInt(&value));
-          base::Value new_int(value);
           if (cur_dict) {
-            cur_dict->SetKey(ReadKeyName(it), std::move(new_int));
+            cur_dict->SetIntKey(ReadKeyName(it), value);
           } else {
-            cur_list->GetList().push_back(std::move(new_int));
+            cur_list->GetList().emplace_back(value);
           }
         } break;
 
         case kTypeDouble: {
           double value;
           CHECK(it.ReadDouble(&value));
-          base::Value new_double(value);
           if (cur_dict) {
-            cur_dict->SetKey(ReadKeyName(it), std::move(new_double));
+            cur_dict->SetDoubleKey(ReadKeyName(it), value);
           } else {
-            cur_list->GetList().push_back(std::move(new_double));
+            cur_list->GetList().emplace_back(value);
           }
         } break;
 
         case kTypeString: {
           std::string value;
           CHECK(it.ReadString(&value));
-          base::Value new_str(std::move(value));
           if (cur_dict) {
-            cur_dict->SetKey(ReadKeyName(it), std::move(new_str));
+            cur_dict->SetStringKey(ReadKeyName(it), std::move(value));
           } else {
-            cur_list->GetList().push_back(std::move(new_str));
+            cur_list->GetList().emplace_back(std::move(value));
           }
         } break;
 
Index: chromium-74.0.3729.108/base/values.cc
===================================================================
--- chromium-74.0.3729.108.orig/base/values.cc
+++ chromium-74.0.3729.108/base/values.cc
@@ -381,11 +381,11 @@ bool Value::RemoveKey(StringPiece key) {
   return dict_.erase(key) != 0;
 }
 
-Value* Value::SetKey(StringPiece key, Value&& value) {
+Value* Value::SetKeyInternal(StringPiece key,
+                             std::unique_ptr<Value>&& val_ptr) {
   CHECK(is_dict());
   // NOTE: We can't use |insert_or_assign| here, as only |try_emplace| does
   // an explicit conversion from StringPiece to std::string if necessary.
-  auto val_ptr = std::make_unique<Value>(std::move(value));
   auto result = dict_.try_emplace(key, std::move(val_ptr));
   if (!result.second) {
     // val_ptr is guaranteed to be still intact at this point.
@@ -394,6 +394,38 @@ Value* Value::SetKey(StringPiece key, Va
   return result.first->second.get();
 }
 
+Value* Value::SetBoolKey(StringPiece key, bool value) {
+  return SetKeyInternal(key, std::make_unique<Value>(value));
+}
+
+Value* Value::SetIntKey(StringPiece key, int value) {
+  return SetKeyInternal(key, std::make_unique<Value>(value));
+}
+
+Value* Value::SetDoubleKey(StringPiece key, double value) {
+  return SetKeyInternal(key, std::make_unique<Value>(value));
+}
+
+Value* Value::SetStringKey(StringPiece key, StringPiece value) {
+  return SetKeyInternal(key, std::make_unique<Value>(value));
+}
+
+Value* Value::SetStringKey(StringPiece key, const char* value) {
+  return SetKeyInternal(key, std::make_unique<Value>(value));
+}
+
+Value* Value::SetStringKey(StringPiece key, std::string&& value) {
+  return SetKeyInternal(key, std::make_unique<Value>(std::move(value)));
+}
+
+Value* Value::SetStringKey(StringPiece key, StringPiece16 value) {
+  return SetKeyInternal(key, std::make_unique<Value>(value));
+}
+
+Value* Value::SetKey(StringPiece key, Value&& value) {
+  return SetKeyInternal(key, std::make_unique<Value>(std::move(value)));
+}
+
 Value* Value::SetKey(std::string&& key, Value&& value) {
   CHECK(is_dict());
   return dict_
@@ -403,7 +435,7 @@ Value* Value::SetKey(std::string&& key,
 }
 
 Value* Value::SetKey(const char* key, Value&& value) {
-  return SetKey(StringPiece(key), std::move(value));
+  return SetKeyInternal(key, std::make_unique<Value>(std::move(value)));
 }
 
 Value* Value::FindPath(std::initializer_list<StringPiece> path) {
Index: chromium-74.0.3729.108/base/values.h
===================================================================
--- chromium-74.0.3729.108.orig/base/values.h
+++ chromium-74.0.3729.108/base/values.h
@@ -222,6 +222,7 @@ class BASE_EXPORT Value {
   // value to |value|. If |key| could not be found, a new element is inserted.
   // A pointer to the modified item is returned.
   // Note: This fatally asserts if type() is not Type::DICTIONARY.
+  // Note: Prefer Set<Type>Key() for simple values.
   //
   // Example:
   //   SetKey("foo", std::move(myvalue));
@@ -231,6 +232,20 @@ class BASE_EXPORT Value {
   // This overload is necessary to avoid ambiguity for const char* arguments.
   Value* SetKey(const char* key, Value&& value);
 
+  // |Set<Type>Key| looks up |key| in the underlying dictionary and associates
+  // a corresponding Value() constructed from the second parameter. Compared
+  // to SetKey(), this avoids un-necessary temporary Value() creation, as well
+  // ambiguities in the value type.
+  Value* SetBoolKey(StringPiece key, bool val);
+  Value* SetIntKey(StringPiece key, int val);
+  Value* SetDoubleKey(StringPiece key, double val);
+  Value* SetStringKey(StringPiece key, StringPiece val);
+  // NOTE: These two overloads are provided as performance / code generation
+  // optimizations.
+  Value* SetStringKey(StringPiece key, const char* val);
+  Value* SetStringKey(StringPiece key, std::string&& val);
+  Value* SetStringKey(StringPiece key, StringPiece16 val);
+
   // This attemps to remove the value associated with |key|. In case of failure,
   // e.g. the key does not exist, |false| is returned and the underlying
   // dictionary is not changed. In case of success, |key| is deleted from the
@@ -469,6 +484,10 @@ class BASE_EXPORT Value {
   void InternalMoveConstructFrom(Value&& that);
   void InternalCleanup();
 
+  // NOTE: Using a movable reference here is done for performance (it avoids
+  // creating + moving + destroying a temporary unique ptr).
+  Value* SetKeyInternal(StringPiece key, std::unique_ptr<Value>&& val_ptr);
+
   DISALLOW_COPY_AND_ASSIGN(Value);
 };
 
Index: chromium-74.0.3729.108/base/values_unittest.cc
===================================================================
--- chromium-74.0.3729.108.orig/base/values_unittest.cc
+++ chromium-74.0.3729.108/base/values_unittest.cc
@@ -794,6 +794,97 @@ TEST(ValuesTest, SetKey) {
   EXPECT_EQ(Value(std::move(storage)), dict);
 }
 
+TEST(ValuesTest, SetBoolKey) {
+  base::Optional<bool> value;
+
+  DictionaryValue dict;
+  dict.SetBoolKey("true_key", true);
+  dict.SetBoolKey("false_key", false);
+
+  value = dict.FindBoolKey("true_key");
+  ASSERT_TRUE(value);
+  ASSERT_TRUE(*value);
+
+  value = dict.FindBoolKey("false_key");
+  ASSERT_TRUE(value);
+  ASSERT_FALSE(*value);
+
+  value = dict.FindBoolKey("missing_key");
+  ASSERT_FALSE(value);
+}
+
+TEST(ValuesTest, SetIntKey) {
+  base::Optional<int> value;
+
+  DictionaryValue dict;
+  dict.SetIntKey("one_key", 1);
+  dict.SetIntKey("minus_one_key", -1);
+
+  value = dict.FindIntKey("one_key");
+  ASSERT_TRUE(value);
+  ASSERT_EQ(1, *value);
+
+  value = dict.FindIntKey("minus_one_key");
+  ASSERT_TRUE(value);
+  ASSERT_EQ(-1, *value);
+
+  value = dict.FindIntKey("missing_key");
+  ASSERT_FALSE(value);
+}
+
+TEST(ValuesTest, SetDoubleKey) {
+  DictionaryValue dict;
+  dict.SetDoubleKey("one_key", 1.0);
+  dict.SetDoubleKey("minus_one_key", -1.0);
+  dict.SetDoubleKey("pi_key", 3.1415);
+
+  // NOTE: Use FindKey() instead of FindDoubleKey() because the latter will
+  // auto-convert integers to doubles as well.
+  const Value* value;
+
+  value = dict.FindKey("one_key");
+  ASSERT_TRUE(value);
+  EXPECT_TRUE(value->is_double());
+  EXPECT_EQ(1.0, value->GetDouble());
+
+  value = dict.FindKey("minus_one_key");
+  ASSERT_TRUE(value);
+  EXPECT_TRUE(value->is_double());
+  EXPECT_EQ(-1.0, value->GetDouble());
+
+  value = dict.FindKey("pi_key");
+  ASSERT_TRUE(value);
+  EXPECT_TRUE(value->is_double());
+  EXPECT_EQ(3.1415, value->GetDouble());
+}
+
+TEST(ValuesTest, SetStringKey) {
+  DictionaryValue dict;
+  dict.SetStringKey("one_key", "one");
+  dict.SetStringKey("hello_key", "hello world");
+
+  std::string movable_value("movable_value");
+  dict.SetStringKey("movable_key", std::move(movable_value));
+  ASSERT_TRUE(movable_value.empty());
+
+  const std::string* value;
+
+  value = dict.FindStringKey("one_key");
+  ASSERT_TRUE(value);
+  ASSERT_EQ("one", *value);
+
+  value = dict.FindStringKey("hello_key");
+  ASSERT_TRUE(value);
+  ASSERT_EQ("hello world", *value);
+
+  value = dict.FindStringKey("movable_key");
+  ASSERT_TRUE(value);
+  ASSERT_EQ("movable_value", *value);
+
+  value = dict.FindStringKey("missing_key");
+  ASSERT_FALSE(value);
+}
+
 TEST(ValuesTest, FindPath) {
   // Construct a dictionary path {root}.foo.bar = 123
   Value foo(Value::Type::DICTIONARY);
@@ -893,7 +984,7 @@ TEST(ValuesTest, Basic) {
   ASSERT_EQ(std::string("http://google.com"), homepage);
 
   ASSERT_FALSE(settings.Get("global", nullptr));
-  settings.SetBoolean("global", true);
+  settings.SetBoolKey("global", true);
   ASSERT_TRUE(settings.Get("global", nullptr));
   settings.SetString("global.homepage", "http://scurvy.com");
   ASSERT_TRUE(settings.Get("global", nullptr));
@@ -911,8 +1002,8 @@ TEST(ValuesTest, Basic) {
   ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
 
   std::unique_ptr<DictionaryValue> new_bookmark(new DictionaryValue);
-  new_bookmark->SetString("name", "Froogle");
-  new_bookmark->SetString("url", "http://froogle.com");
+  new_bookmark->SetStringKey("name", "Froogle");
+  new_bookmark->SetStringKey("url", "http://froogle.com");
   toolbar_bookmarks->Append(std::move(new_bookmark));
 
   ListValue* bookmark_list;
@@ -1276,7 +1367,7 @@ TEST(ValuesTest, DeepCopy) {
 
   DictionaryValue* dict_weak = original_dict.SetDictionary(
       "dictionary", std::make_unique<DictionaryValue>());
-  dict_weak->SetString("key", "value");
+  dict_weak->SetStringKey("key", "value");
 
   auto copy_dict = original_dict.CreateDeepCopy();
   ASSERT_TRUE(copy_dict.get());
@@ -1392,11 +1483,11 @@ TEST(ValuesTest, Equals) {
   EXPECT_NE(*null1, boolean);
 
   DictionaryValue dv;
-  dv.SetBoolean("a", false);
-  dv.SetInteger("b", 2);
-  dv.SetDouble("c", 2.5);
-  dv.SetString("d1", "string");
-  dv.SetString("d2", ASCIIToUTF16("http://google.com"));
+  dv.SetBoolKey("a", false);
+  dv.SetIntKey("b", 2);
+  dv.SetDoubleKey("c", 2.5);
+  dv.SetStringKey("d1", "string");
+  dv.SetStringKey("d2", ASCIIToUTF16("http://google.com"));
   dv.Set("e", std::make_unique<Value>());
 
   auto copy = dv.CreateDeepCopy();
@@ -1419,7 +1510,7 @@ TEST(ValuesTest, Equals) {
   copy = dv.CreateDeepCopy();
   EXPECT_EQ(dv, *copy);
   copy->Remove("a", nullptr);
-  copy->SetBoolean("aa", false);
+  copy->SetBoolKey("aa", false);
   EXPECT_NE(dv, *copy);
 }
 
@@ -1519,8 +1610,8 @@ TEST(ValuesTest, Comparisons) {
   // Test Non Empty Dict Values.
   DictionaryValue int_dict1;
   DictionaryValue int_dict2;
-  int_dict1.SetInteger("key", 1);
-  int_dict2.SetInteger("key", 2);
+  int_dict1.SetIntKey("key", 1);
+  int_dict2.SetIntKey("key", 2);
   EXPECT_FALSE(int_dict1 == int_dict2);
   EXPECT_NE(int_dict1, int_dict2);
   EXPECT_LT(int_dict1, int_dict2);
@@ -1599,9 +1690,9 @@ TEST(ValuesTest, RemoveEmptyChildren) {
   EXPECT_TRUE(root->empty());
 
   // Make sure we don't prune too much.
-  root->SetBoolean("bool", true);
+  root->SetBoolKey("bool", true);
   root->Set("empty_dict", std::make_unique<DictionaryValue>());
-  root->SetString("empty_string", std::string());
+  root->SetStringKey("empty_string", std::string());
   root = root->DeepCopyWithoutEmptyChildren();
   EXPECT_EQ(2U, root->size());
 
@@ -1668,19 +1759,20 @@ TEST(ValuesTest, RemoveEmptyChildren) {
 
 TEST(ValuesTest, MergeDictionary) {
   std::unique_ptr<DictionaryValue> base(new DictionaryValue);
-  base->SetString("base_key", "base_key_value_base");
-  base->SetString("collide_key", "collide_key_value_base");
+  base->SetStringKey("base_key", "base_key_value_base");
+  base->SetStringKey("collide_key", "collide_key_value_base");
   std::unique_ptr<DictionaryValue> base_sub_dict(new DictionaryValue);
-  base_sub_dict->SetString("sub_base_key", "sub_base_key_value_base");
-  base_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_base");
+  base_sub_dict->SetStringKey("sub_base_key", "sub_base_key_value_base");
+  base_sub_dict->SetStringKey("sub_collide_key", "sub_collide_key_value_base");
   base->Set("sub_dict_key", std::move(base_sub_dict));
 
   std::unique_ptr<DictionaryValue> merge(new DictionaryValue);
-  merge->SetString("merge_key", "merge_key_value_merge");
-  merge->SetString("collide_key", "collide_key_value_merge");
+  merge->SetStringKey("merge_key", "merge_key_value_merge");
+  merge->SetStringKey("collide_key", "collide_key_value_merge");
   std::unique_ptr<DictionaryValue> merge_sub_dict(new DictionaryValue);
-  merge_sub_dict->SetString("sub_merge_key", "sub_merge_key_value_merge");
-  merge_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_merge");
+  merge_sub_dict->SetStringKey("sub_merge_key", "sub_merge_key_value_merge");
+  merge_sub_dict->SetStringKey("sub_collide_key",
+                               "sub_collide_key_value_merge");
   merge->Set("sub_dict_key", std::move(merge_sub_dict));
 
   base->MergeDictionary(merge.get());
@@ -1714,7 +1806,7 @@ TEST(ValuesTest, MergeDictionary) {
 TEST(ValuesTest, MergeDictionaryDeepCopy) {
   std::unique_ptr<DictionaryValue> child(new DictionaryValue);
   DictionaryValue* original_child = child.get();
-  child->SetString("test", "value");
+  child->SetStringKey("test", "value");
   EXPECT_EQ(1U, child->size());
 
   std::string value;
@@ -1737,7 +1829,7 @@ TEST(ValuesTest, MergeDictionaryDeepCopy
   EXPECT_TRUE(ptr->GetString("test", &value));
   EXPECT_EQ("value", value);
 
-  original_child->SetString("test", "overwrite");
+  original_child->SetStringKey("test", "overwrite");
   base.reset();
   EXPECT_TRUE(ptr->GetString("test", &value));
   EXPECT_EQ("value", value);
@@ -2104,8 +2196,8 @@ TEST(ValuesTest, SelfSwap) {
 
 TEST(ValuesTest, FromToUniquePtrValue) {
   std::unique_ptr<DictionaryValue> dict = std::make_unique<DictionaryValue>();
-  dict->SetString("name", "Froogle");
-  dict->SetString("url", "http://froogle.com");
+  dict->SetStringKey("name", "Froogle");
+  dict->SetStringKey("url", "http://froogle.com");
   Value dict_copy = dict->Clone();
 
   Value dict_converted = Value::FromUniquePtrValue(std::move(dict));