Provide bespoke types for dictionaries and lists of base::Values.

The proposal for updating base::Value to a value type flattened the
convenience APIs for working with dictionaries and lists directly into
base::Value. In addition, it was believed that most code working with
dictionaries and lists could be directly use the underlying types
(base::flat_map<std::string, base::Value> and std::vector<base::Value>)
instead.

However, the migration to the updated API has resulted in several
non-optimal outcomes:

- Using the raw container types directly leads to bloat in the generated
  code due to the required repetition of boilerplate code.
- Using the flattened base::Value convenience methods leads to a loss in
  type safety: code that is only using a base::Value to use the
  dictionary methods now relies on runtime checks to ensure that
  incorrect inputs are not supplied.
- Exposing the raw container types makes it harder to refactor
  implementation details in the future.

This CL reimplements distinct types for dictionaries and lists of
base::Values and updates base::Value to use these new types as the
internal representation. With the exception of APIs slated for removal,
many of the flattened APIs have already been migrated to internally use
the updated implementation as well.

Additional changes in this CL:
- Methods that work directly with the various subtypes now consistently
  act on the same set of overloads (with the exception of constructors
  for legacy reasons).
- Dictionary APIs that work with keys no longer have a 'Key' suffix.
- Dictionary APIs that work with paths now have a 'ByDottedPath' suffix
  instead. There is fairly consistent, yet unnecessary, use of the path
  methods; hopefully, the new, more verbose, suffix will make it clear
  that special processing happens for paths.
- Dictionary APIs that work with paths now enforce a consistent set of
  rules. Previously, empty paths were sometimes allowed, but empty paths
  are never allowed now.
- A hack to allow JSON serialization to work with the new dictionary and
  list subtypes without requiring that they be cloned into a base::Value
  wrapper. A followup will implement a proper view type for base::Value
  to enable these use cases without code duplication.

Bug: 1291666, 1291670
Change-Id: Ie5361449d67a66de48756c1049015dd09464543d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3443197
Reviewed-by: Finnur Thorarinsson <[email protected]>
Reviewed-by: Pavol Marko <[email protected]>
Reviewed-by: Gabriel Charette <[email protected]>
Reviewed-by: Nektarios Paisios <[email protected]>
Reviewed-by: Jan Wilken Dörrie <[email protected]>
Commit-Queue: Daniel Cheng <[email protected]>
Cr-Commit-Position: refs/heads/main@{#971315}
diff --git a/base/value_iterators.h b/base/value_iterators.h
index 92f7357..6081c6b 100644
--- a/base/value_iterators.h
+++ b/base/value_iterators.h
@@ -62,6 +62,14 @@
   BASE_EXPORT friend bool operator!=(const dict_iterator& lhs,
                                      const dict_iterator& rhs);
 
+  // Currently, there is no easy way to friend Value::Dict. Once dictionary
+  // storage is updated to not require a proxy iterator, the implementation can
+  // be folded into //base/values.h and a standard friend declaration can be
+  // used instead.
+  const DictStorage::iterator& GetUnderlyingIteratorDoNotUse() {
+    return dict_iter_;
+  }
+
  private:
   DictStorage::iterator dict_iter_;
 };
@@ -108,6 +116,14 @@
   BASE_EXPORT friend bool operator!=(const const_dict_iterator& lhs,
                                      const const_dict_iterator& rhs);
 
+  // Currently, there is no easy way to friend Value::Dict. Once dictionary
+  // storage is updated to not require a proxy iterator, the implementation can
+  // be folded into //base/values.h and a standard friend declaration can be
+  // used instead.
+  const DictStorage::const_iterator& GetUnderlyingIteratorDoNotUse() {
+    return dict_iter_;
+  }
+
  private:
   DictStorage::const_iterator dict_iter_;
 };