// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_VALUES_H_ #define BASE_VALUES_H_ #include #include #include #include #include #include #include #include #include #include "base/base_export.h" #include "base/bit_cast.h" #include "base/compiler_specific.h" #include "base/containers/checked_iterators.h" #include "base/containers/checked_range.h" #include "base/containers/cxx20_erase_vector.h" #include "base/containers/flat_map.h" #include "base/containers/span.h" #include "base/strings/string_piece.h" #include "base/trace_event/base_tracing_forward.h" #include "base/value_iterators.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/abseil-cpp/absl/types/variant.h" namespace base { class DictionaryValue; class ListValue; // The `Value` class is a variant type can hold one of the following types: // - null // - bool // - int // - double // - string (internally UTF8-encoded) // - binary data (i.e. a blob) // - dictionary of string keys to `Value`s // - list of `Value`s // // With the exception of binary blobs, `Value` is intended to be the C++ version // of data types that can be represented in JSON. // // Warning: blob support may be removed in the future. // // ## Usage // // Do not use `Value` if a more specific type would be more appropriate. For // example, a function that only accepts dictionary values should have a // `base::Value::Dict` parameter, not a `base::Value` parameter. // // Construction: // // `Value` is directly constructible from `bool`, `int`, `double`, binary blobs // (`std::vector`), `base::StringPiece`, `base::StringPiece16`, // `Value::Dict`, and `Value::List`. // // Copying: // // `Value` does not support C++ copy semantics to make it harder to accidentally // copy large values. Instead, use `Clone()` to manually create a deep copy. // // Reading: // // `GetBool()`, GetInt()`, et cetera `CHECK()` that the `Value` has the correct // subtype before returning the contained value. `bool`, `int`, `double` are // returned by value. Binary blobs, `std::string`, `Value::Dict`, `Value::List` // are returned by reference. // // `GetIfBool()`, `GetIfInt()`, et cetera return `absl::nullopt`/`nullptr` if // the `Value` does not have the correct subtype; otherwise, returns the value // wrapped in an `absl::optional` (for `bool`, `int`, `double`) or by pointer // (for binary blobs, `std::string`, `Value::Dict`, `Value::List`). // // Note: both `GetDouble()` and `GetIfDouble()` still return a non-null result // when the subtype is `Value::Type::INT`. In that case, the stored value is // coerced to a double before being returned. // // Assignment: // // It is not possible to directly assign `bool`, `int`, et cetera to a `Value`. // Instead, wrap the underlying type in `Value` before assigning. // // ## Dictionaries and Lists // // `Value` provides the `Value::Dict` and `Value::List` container types for // working with dictionaries and lists of values respectively, rather than // exposing the underlying container types directly. This allows the types to // provide convenient helpers for dictionaries and lists, as well as giving // greater flexibility for changing implementation details in the future. // // Both container types support enough STL-isms to be usable in range-based for // loops and generic operations such as those from . // // Dictionaries support: // - `empty()`, `size()`, `begin()`, `end()`, `cbegin()`, `cend()`, // `contains()`, `clear()`, `erase()`: Identical to the STL container // equivalents, with additional safety checks, e.g. iterators will // `CHECK()` if `end()` is dereferenced. // // - `Clone()`: Create a deep copy. // - `Merge()`: Merge another dictionary into this dictionary. // - `Find()`: Find a value by `StringPiece` key, returning nullptr if the key // is not present. // - `FindBool()`, `FindInt()`, ...: Similar to `Find()`, but ensures that the // `Value` also has the correct subtype. Same return semantics as // `GetIfBool()`, `GetIfInt()`, et cetera, returning `absl::nullopt` or // `nullptr` if the key is not present or the value has the wrong subtype. // - `Set()`: Associate a value with a `StringPiece` key. Accepts `Value` or any // of the subtypes that `Value` can hold. // - `Remove()`: Remove the key from this dictionary, if present. // - `Extract()`: If the key is present in the dictionary, removes the key from // the dictionary and transfers ownership of `Value` to the caller. // Otherwise, returns `absl::nullopt`. // // Dictionaries also support an additional set of helper methods that operate on // "paths": `FindByDottedPath()`, `SetByDottedPath()`, `RemoveByDottedPath()`, // and `ExtractByDottedPath()`. Dotted paths are a convenience method of naming // intermediate nested dictionaries, separating the components of the path using // '.' characters. For example, finding a string path on a `Value::Dict` using // the dotted path: // // "aaa.bbb.ccc" // // Will first look for a `Value::Type::DICT` associated with the key "aaa", then // another `Value::Type::DICT` under the "aaa" dict associated with the // key "bbb", and then a `Value::Type::STRING` under the "bbb" dict associated // with the key "ccc". // // If a path only has one component (i.e. has no dots), please use the regular, // non-path APIs. // // Lists support: // - `empty()`, `size()`, `begin()`, `end()`, `cbegin()`, `cend()`, // `operator[]`, `clear()`, `erase()`: Identical to the STL container // equivalents, with additional safety checks, e.g. `operator[]` will // `CHECK()` if the index is out of range. // - `Clone()`: Create a deep copy. // - `Append()`: Append a value to the end of the list. Accepts `Value` or any // of the subtypes that `Value` can hold. // - `Insert()`: Insert a `Value` at a specified point in the list. // - `EraseValue()`: Erases all matching `Value`s from the list. // - `EraseIf()`: Erase all `Value`s matching an arbitrary predicate from the // list. // // ## Refactoring Notes // // `Value` was originally implemented as a class hierarchy, with a `Value` base // class, and a leaf class for each of the different types of `Value` subtypes. // https://docs.google.com/document/d/1uDLu5uTRlCWePxQUEHc8yNQdEoE1BDISYdpggWEABnw // proposed an overhaul of the `Value` API that has now largely been // implemented, though there remains a significant amount of legacy code that is // still being migrated as part of the code health migration. // // OLD WAY: // // std::unique_ptr GetFoo() { // std::unique_ptr dict; // dict->SetString("mykey", "foo"); // return dict; // } // // NEW WAY: // // base::Value GetFoo() { // base::Value::Dict dict; // dict.SetString("mykey", "abc"); // return base::Value(std::move(dict)); // } // // To avoid losing type information with the new variant-based design, migration // off the deprecated types should use more specific subtypes where possible: // // OLD WAY: // // void AlwaysTakesList(std::unique_ptr list); // void AlwaysTakesDict(std::unique_ptr dict); // // DEPRECATED (PREVIOUS) WAY: // // void AlwaysTakesList(std::vector list); // void AlwaysTakesListAlternative1(base::Value::ConstListView list); // void AlwaysTakesListAlternative2(base::Value::ListView& list); // void AlwaysTakesListAlterantive3(base::Value::ListStorage); // void AlwaysTakesDict(base::flat_map dict); // void AlwaysTakesDictAlternative(base::Value::DictStorage); // // NEW WAY: // // void AlwaysTakesList(base::Value::List list); // void AlwaysTakesDict(base::Value::Dict dict); // // Migrating code may require conversions on API boundaries. If something seems // awkward/inefficient, please reach out to #code-health-rotation on Slack for // consultation: it is entirely possible that certain classes of APIs may be // missing due to an unrealized need. class BASE_EXPORT GSL_OWNER Value { public: using BlobStorage = std::vector; using DeprecatedListStorage = std::vector; using DeprecatedDictStorage = flat_map; // TODO(https://crbug.com/1291666): Make these private. using ListStorage = DeprecatedListStorage; using DictStorage = DeprecatedDictStorage; // Like `DictStorage`, but with std::unique_ptr in the mapped type. This is // due to legacy reasons, and should be removed once no caller relies on // stability of pointers anymore. using LegacyDictStorage = flat_map>; using DeprecatedListView = CheckedContiguousRange; using DeprecatedConstListView = CheckedContiguousConstRange; // TODO(https://crbug.com/1291666): Make these private. using ListView = DeprecatedListView; using ConstListView = DeprecatedConstListView; class Dict; class List; enum class Type : unsigned char { NONE = 0, BOOLEAN, INTEGER, DOUBLE, STRING, BINARY, DICT, // TODO(https://crbug.com/1291670): Deprecated and will be removed. DICTIONARY = DICT, LIST, // Note: Do not add more types. See the file-level comment above for why. }; // Adaptors for converting from the old way to the new way and vice versa. static Value FromUniquePtrValue(std::unique_ptr val); static std::unique_ptr ToUniquePtrValue(Value val); static const DictionaryValue& AsDictionaryValue(const Value& val); static const ListValue& AsListValue(const Value& val); Value() noexcept; Value(Value&&) noexcept; Value& operator=(Value&&) noexcept; // Deleted to prevent accidental copying. Value(const Value&) = delete; Value& operator=(const Value&) = delete; // Creates a deep copy of this value. Value Clone() const; // Creates a `Value` of `type`. The data of the corresponding type will be // default constructed. explicit Value(Type type); // Constructor for `Value::Type::BOOLEAN`. explicit Value(bool value); // Prevent pointers from implicitly converting to bool. Another way to write // this would be to template the bool constructor and use SFINAE to only allow // use if `std::is_same_v` is true, but this has surprising behavior // with range-based for loops over a `std::vector` (which will // unintuitively match the int overload instead). // // The `const` is load-bearing; otherwise, a `char*` argument would prefer the // deleted overload due to requiring a qualification conversion. template explicit Value(const T*) = delete; // Constructor for `Value::Type::INT`. explicit Value(int value); // Constructor for `Value::Type::DOUBLE`. explicit Value(double value); // Constructors for `Value::Type::STRING`. explicit Value(StringPiece value); explicit Value(StringPiece16 value); // `char*` and `char16_t*` are needed to provide a more specific overload than // the deleted `const T*` overload above. explicit Value(const char* value); explicit Value(const char16_t* value); // `std::string&&` allows for efficient move construction. explicit Value(std::string&& value) noexcept; // Constructors for `Value::Type::BINARY`. explicit Value(const std::vector& value); explicit Value(base::span value); explicit Value(BlobStorage&& value) noexcept; // Constructor for `Value::Type::DICT`. explicit Value(Dict&& value) noexcept; // Constructor for `Value::Type::LIST`. explicit Value(List&& value) noexcept; // DEPRECATED: prefer `Value(Dict&&)`. explicit Value(const DictStorage& value); explicit Value(DictStorage&& value); // DEPRECATED: prefer `Value(List&&)`. explicit Value(span value); explicit Value(ListStorage&& value) noexcept; ~Value(); // Returns the name for a given `type`. static const char* GetTypeName(Type type); // Returns the type of the value stored by the current Value object. Type type() const { return static_cast(data_.index()); } // Returns true if the current object represents a given type. bool is_none() const { return type() == Type::NONE; } bool is_bool() const { return type() == Type::BOOLEAN; } bool is_int() const { return type() == Type::INTEGER; } bool is_double() const { return type() == Type::DOUBLE; } bool is_string() const { return type() == Type::STRING; } bool is_blob() const { return type() == Type::BINARY; } bool is_dict() const { return type() == Type::DICT; } bool is_list() const { return type() == Type::LIST; } // Returns the stored data if the type matches, or `absl::nullopt`/`nullptr` // otherwise. `bool`, `int`, and `double` are returned in a wrapped // `absl::optional`; blobs, `Value::Dict`, and `Value::List` are returned by // pointer. absl::optional GetIfBool() const; absl::optional GetIfInt() const; // Returns a non-null value for both `Value::Type::DOUBLE` and // `Value::Type::INT`, converting the latter to a double. absl::optional GetIfDouble() const; const std::string* GetIfString() const; std::string* GetIfString(); const BlobStorage* GetIfBlob() const; const Dict* GetIfDict() const; Dict* GetIfDict(); const List* GetIfList() const; List* GetIfList(); // Similar to the `GetIf...()` variants above, but fails with a `CHECK()` on a // type mismatch. `bool`, `int`, and `double` are returned by value; blobs, // `Value::Dict`, and `Value::List` are returned by reference. bool GetBool() const; int GetInt() const; // Returns a value for both `Value::Type::DOUBLE` and `Value::Type::INT`, // converting the latter to a double. double GetDouble() const; const std::string& GetString() const; std::string& GetString(); const BlobStorage& GetBlob() const; const Dict& GetDict() const; Dict& GetDict(); const List& GetList() const; List& GetList(); // Represents a dictionary of string keys to Values. class BASE_EXPORT GSL_OWNER Dict { public: using iterator = detail::dict_iterator; using const_iterator = detail::const_dict_iterator; Dict(); Dict(Dict&&) noexcept; Dict& operator=(Dict&&) noexcept; // Deleted to prevent accidental copying. Dict(const Dict&) = delete; Dict& operator=(const Dict&) = delete; ~Dict(); // TODO(dcheng): Probably need to allow construction from a pair of // iterators for now due to the prevalence of DictStorage. // Returns true if there are no entries in this dictionary and false // otherwise. bool empty() const; // Returns the number of entries in this dictionary. size_t size() const; // Returns an iterator to the first entry in this dictionary. iterator begin(); const_iterator begin() const; const_iterator cbegin() const; // Returns an iterator following the last entry in this dictionary. May not // be dereferenced. iterator end(); const_iterator end() const; const_iterator cend() const; // Returns true if `key` is an entry in this dictionary. bool contains(base::StringPiece key) const; // Removes all entries from this dictionary. void clear(); // Removes the entry referenced by `pos` in this dictionary and returns an // iterator to the entry following the removed entry. iterator erase(iterator pos); iterator erase(const_iterator pos); // Creates a deep copy of this dictionary. Dict Clone() const; // Merges the entries from `dict` into this dictionary. If an entry with the // same key exists in this dictionary and `dict`: // - if both entries are dictionaries, they will be recursively merged // - otherwise, the already-existing entry in this dictionary will be // overwritten with the entry from `dict`. void Merge(const Dict& dict); // Finds the entry corresponding to `key` in this dictionary. Returns // nullptr if there is no such entry. const Value* Find(StringPiece key) const; Value* Find(StringPiece key); // Similar to `Find()` above, but returns `absl::nullopt`/`nullptr` if the // type of the entry does not match. `bool`, `int`, and `double` are // returned in a wrapped `absl::optional`; blobs, `Value::Dict`, and // `Value::List` are returned by pointer. absl::optional FindBool(StringPiece key) const; absl::optional FindInt(StringPiece key) const; // Returns a non-null value for both `Value::Type::DOUBLE` and // `Value::Type::INT`, converting the latter to a double. absl::optional FindDouble(StringPiece key) const; const std::string* FindString(StringPiece key) const; std::string* FindString(StringPiece key); const BlobStorage* FindBlob(StringPiece key) const; const Dict* FindDict(StringPiece key) const; Dict* FindDict(StringPiece key); const List* FindList(StringPiece key) const; List* FindList(StringPiece key); // Sets an entry with `key` and `value` in this dictionary, overwriting any // existing entry with the same `key`. Returns a pointer to the set `value`. Value* Set(StringPiece key, Value&& value); Value* Set(StringPiece key, bool value); template Value* Set(StringPiece, const T*) = delete; Value* Set(StringPiece key, int value); Value* Set(StringPiece key, double value); Value* Set(StringPiece key, StringPiece value); Value* Set(StringPiece key, StringPiece16 value); Value* Set(StringPiece key, const char* value); Value* Set(StringPiece key, const char16_t* value); Value* Set(StringPiece key, std::string&& value); Value* Set(StringPiece key, BlobStorage&& value); Value* Set(StringPiece key, Dict&& value); Value* Set(StringPiece key, List&& value); // Removes the entry corresponding to `key` from this dictionary. Returns // true if an entry was removed or false otherwise. bool Remove(StringPiece key); // Similar to `Remove()`, but returns the value corresponding to the removed // entry or `absl::nullopt` otherwise. absl::optional Extract(StringPiece key); // Equivalent to the above methods but operating on paths instead of keys. // A path is shorthand syntax for referring to a key nested inside // intermediate dictionaries, with components delimited by ".". Paths may // not be empty. // // Prefer the non-path methods above when possible. Paths that have only one // component (i.e. no dots in the path) should never use the path-based // methods. // // Originally, the path-based APIs were the only way of specifying a key, so // there are likely to be many legacy (and unnecessary) uses of the path // APIs that do not actually require traversing nested dictionaries. const Value* FindByDottedPath(StringPiece path) const; Value* FindByDottedPath(StringPiece path); absl::optional FindBoolByDottedPath(StringPiece path) const; absl::optional FindIntByDottedPath(StringPiece path) const; // Returns a non-null value for both `Value::Type::DOUBLE` and // `Value::Type::INT`, converting the latter to a double. absl::optional FindDoubleByDottedPath(StringPiece path) const; const std::string* FindStringByDottedPath(StringPiece path) const; std::string* FindStringByDottedPath(StringPiece path); const BlobStorage* FindBlobByDottedPath(StringPiece path) const; const Dict* FindDictByDottedPath(StringPiece path) const; Dict* FindDictByDottedPath(StringPiece path); const List* FindListByDottedPath(StringPiece path) const; List* FindListByDottedPath(StringPiece path); // Creates a new entry with a dictionary for any non-last component that is // missing an entry while performing the path traversal. Will fail if any // non-last component of the path refers to an already-existing entry that // is not a dictionary. Returns `nullptr` on failure. Value* SetByDottedPath(StringPiece path, Value&& value); Value* SetByDottedPath(StringPiece path, bool value); template Value* SetByDottedPath(StringPiece, const T*) = delete; Value* SetByDottedPath(StringPiece path, int value); Value* SetByDottedPath(StringPiece path, double value); Value* SetByDottedPath(StringPiece path, StringPiece value); Value* SetByDottedPath(StringPiece path, StringPiece16 value); Value* SetByDottedPath(StringPiece path, const char* value); Value* SetByDottedPath(StringPiece path, const char16_t* value); Value* SetByDottedPath(StringPiece path, std::string&& value); Value* SetByDottedPath(StringPiece path, BlobStorage&& value); Value* SetByDottedPath(StringPiece path, Dict&& value); Value* SetByDottedPath(StringPiece path, List&& value); bool RemoveByDottedPath(StringPiece path); absl::optional ExtractByDottedPath(StringPiece path); private: BASE_EXPORT friend bool operator==(const Dict& lhs, const Dict& rhs); BASE_EXPORT friend bool operator!=(const Dict& lhs, const Dict& rhs); BASE_EXPORT friend bool operator<(const Dict& lhs, const Dict& rhs); BASE_EXPORT friend bool operator>(const Dict& lhs, const Dict& rhs); BASE_EXPORT friend bool operator<=(const Dict& lhs, const Dict& rhs); BASE_EXPORT friend bool operator>=(const Dict& lhs, const Dict& rhs); // For legacy access to the internal storage type. friend Value; explicit Dict(const flat_map>& storage); flat_map> storage_; }; // Represents a list of Values. class BASE_EXPORT GSL_OWNER List { public: using iterator = CheckedContiguousIterator; using const_iterator = CheckedContiguousConstIterator; List(); List(List&&) noexcept; List& operator=(List&&) noexcept; // Deleted to prevent accidental copying. List(const List&) = delete; List& operator=(const List&) = delete; ~List(); // TODO(dcheng): Probably need to allow construction from a pair of // iterators for now due to the prevalence of ListStorage now. // Returns true if there are no values in this list and false otherwise. bool empty() const; // Returns the number of values in this list. size_t size() const; // Returns an iterator to the first value in this list. iterator begin(); const_iterator begin() const; const_iterator cbegin() const; // Returns an iterator following the last value in this list. May not be // dereferenced. iterator end(); const_iterator end() const; const_iterator cend() const; // Returns a reference to the value at `index` in this list. Fails with a // `CHECK()` if `index >= size()`. const Value& operator[](size_t index) const; Value& operator[](size_t index); // Removes all value from this list. void clear(); // Removes the value referenced by `pos` in this listand returns an iterator // to the value following the removed value. iterator erase(iterator pos); const_iterator erase(const_iterator pos); // Creates a deep copy of this dictionary. List Clone() const; // Appends `value` to the end of this list. void Append(Value&& value); void Append(bool value); template void Append(const T*) = delete; void Append(int value); void Append(double value); void Append(StringPiece value); void Append(StringPiece16 value); void Append(const char* value); void Append(const char16_t* value); void Append(std::string&& value); void Append(BlobStorage&& value); void Append(Dict&& value); void Append(List&& value); // Inserts `value` before `pos` in this list. Returns an iterator to the // inserted value. // TODO(dcheng): Should this provide the same set of overloads that Append() // does? iterator Insert(const_iterator pos, Value&& value); // Erases all values equal to `value` from this list. size_t EraseValue(const Value& value); // Erases all values for which `predicate` evaluates to true from this list. template size_t EraseIf(Predicate predicate) { return base::EraseIf(storage_, predicate); } private: BASE_EXPORT friend bool operator==(const List& lhs, const List& rhs); BASE_EXPORT friend bool operator!=(const List& lhs, const List& rhs); BASE_EXPORT friend bool operator<(const List& lhs, const List& rhs); BASE_EXPORT friend bool operator>(const List& lhs, const List& rhs); BASE_EXPORT friend bool operator<=(const List& lhs, const List& rhs); BASE_EXPORT friend bool operator>=(const List& lhs, const List& rhs); // For legacy access to the internal storage type. friend Value; explicit List(const std::vector& storage); std::vector storage_; }; // ===== DEPRECATED methods that require `type() == Type::LIST` ===== // Returns the Values in a list as a view. The mutable overload allows for // modification of the underlying values, but does not allow changing the // structure of the list. If this is desired, use `TakeListDeprecated()`, // perform the operations, and return the list back to the Value via move // assignment. // // DEPRECATED: prefer direct use `base::Value::List` where possible, or // `GetList()` otherwise. DeprecatedListView GetListDeprecated(); DeprecatedConstListView GetListDeprecated() const; // Transfers ownership of the underlying list to the caller. Subsequent // calls to `GetListDeprecated()` will return an empty list. // // DEPRECATED: prefer direct use of `base::Value::List` where possible, or // `std::move(value.GetList())` otherwise. DeprecatedListStorage TakeListDeprecated() &&; // Appends `value` to the end of the list. // // DEPRECATED: prefer `Value::List::Append()`. void Append(Value&& value); // DEPRECATED: prefer `Value::List::Append()`. void Append(bool value); template void Append(const T* ptr) = delete; // DEPRECATED: prefer `Value::List::Append()`. void Append(int value); // DEPRECATED: prefer `Value::List::Append()`. void Append(double value); // DEPRECATED: prefer `Value::List::Append()`. void Append(StringPiece value); // DEPRECATED: prefer `Value::List::Append()`. void Append(StringPiece16 value); // DEPRECATED: prefer `Value::List::Append()`. void Append(const char* value); // DEPRECATED: prefer `Value::List::Append()`. void Append(const char16_t* value); // DEPRECATED: prefer `Value::List::Append()`. void Append(std::string&& value); // Inserts `value` before `pos`. // // DEPRECATED: prefer `Value::List::Insert()`. CheckedContiguousIterator Insert( CheckedContiguousConstIterator pos, Value&& value); // Erases the Value pointed to by `iter`. Returns false if `iter` is out of // bounds. // // DEPRECATED: prefer `Value::List::erase(iter)`. bool EraseListIter(CheckedContiguousConstIterator iter); // Erases all Values that compare equal to `val`. Returns the number of // deleted Values. // // DEPRECATED: prefer `Value::List::EraseValue(val)`. size_t EraseListValue(const Value& val); // Erases all Values for which `pred` returns true. Returns the number of // deleted Values. // // DEPRECATED: prefer `Value::List::EraseIf(pred)`. template size_t EraseListValueIf(Predicate pred) { return base::EraseIf(list(), pred); } // Erases all Values from the list. // // DEPRECATED: prefer `Value::List::clear()`. void ClearList(); // ===== DEPRECATED methods that require `type() == Type::DICT` ===== // `FindKey` looks up `key` in the underlying dictionary. If found, it returns // a pointer to the element. Otherwise it returns nullptr. // // DEPRECATED: prefer `Value::Dict::Find()`. Value* FindKey(StringPiece key); const Value* FindKey(StringPiece key) const; // `FindKeyOfType` is similar to `FindKey`, but it also requires the found // value to have type `type`. If no type is found, or the found value is of a // different type nullptr is returned. // // DEPRECATED: prefer `Value::Dict::FindBool()`, `Value::Dict::FindInt()`, et // cetera. Value* FindKeyOfType(StringPiece key, Type type); const Value* FindKeyOfType(StringPiece key, Type type) const; // These are convenience forms of `FindKey`. They return `absl::nullopt` or // `nullptr` if the value is not found or doesn't have the type specified in // the function's name. // // DEPRECATED: prefer `Value::Dict::FindBool()`. absl::optional FindBoolKey(StringPiece key) const; // DEPRECATED: prefer `Value::Dict::FindInt()`. absl::optional FindIntKey(StringPiece key) const; // Returns a non-null value for both `Value::Type::DOUBLE` and // `Value::Type::INT`, converting the latter to a double. // // DEPRECATED: prefer `Value::Dict::FindDouble()`. absl::optional FindDoubleKey(StringPiece key) const; // DEPRECATED: prefer `Value::Dict::FindString()`. const std::string* FindStringKey(StringPiece key) const; std::string* FindStringKey(StringPiece key); // DEPRECATED: prefer `Value::Dict::FindBlob()`. const BlobStorage* FindBlobKey(StringPiece key) const; // DEPRECATED: prefer `Value::Dict::FindDict()`. const Value* FindDictKey(StringPiece key) const; Value* FindDictKey(StringPiece key); // DEPRECATED: prefer `Value::Dict::FindList()`. const Value* FindListKey(StringPiece key) const; Value* FindListKey(StringPiece key); // `SetKey` looks up `key` in the underlying dictionary and sets the mapped // value to `value`. If `key` could not be found, a new element is inserted. // A pointer to the modified item is returned. // // Note: Prefer `SetKey()` if the input is not already a `Value`. // // DEPRECATED: Prefer `Value::Dict::Set()`. Value* SetKey(StringPiece 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. // // DEPRECATED: Prefer `Value::Dict::Set()`. Value* SetBoolKey(StringPiece key, bool val); // DEPRECATED: Prefer `Value::Dict::Set()`. Value* SetIntKey(StringPiece key, int val); // DEPRECATED: Prefer `Value::Dict::Set()`. Value* SetDoubleKey(StringPiece key, double val); // DEPRECATED: Prefer `Value::Dict::Set()`. Value* SetStringKey(StringPiece key, StringPiece val); // DEPRECATED: Prefer `Value::Dict::Set()`. Value* SetStringKey(StringPiece key, StringPiece16 val); // DEPRECATED: Prefer `Value::Dict::Set()`. Value* SetStringKey(StringPiece key, const char* val); // DEPRECATED: Prefer `Value::Dict::Set()`. Value* SetStringKey(StringPiece key, std::string&& val); // This attempts 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 // dictionary and the method returns true. // // Deprecated: Prefer `Value::Dict::Remove()`. bool RemoveKey(StringPiece key); // This attempts to extract the value associated with `key`. In case of // failure, e.g. the key does not exist, nullopt is returned and the // underlying dictionary is not changed. In case of success, `key` is deleted // from the dictionary and the method returns the extracted Value. // // DEPRECATED: Prefer `Value::Dict::Extract()`. absl::optional ExtractKey(StringPiece key); // Searches a hierarchy of dictionary values for a given value. If a path // of dictionaries exist, returns the item at that path. If any of the path // components do not exist or if any but the last path components are not // dictionaries, returns nullptr. The type of the leaf Value is not checked. // // This version takes a StringPiece for the path, using dots as separators. // // DEPRECATED: Prefer `Value::Dict::FindByDottedPath()`. Value* FindPath(StringPiece path); const Value* FindPath(StringPiece path) const; // There are also deprecated versions that take the path parameter // as either a std::initializer_list or a // span. The latter is useful to use a // std::vector as a parameter but creates huge dynamic // allocations and should be avoided! // Note: If there is only one component in the path, use `FindKey()` instead. // // Example: // std::vector components = ... // auto* found = FindPath(components); // // DEPRECATED: These are not common, and there is no currently planned // replacement. Value* FindPath(std::initializer_list path); Value* FindPath(span path); const Value* FindPath(std::initializer_list path) const; const Value* FindPath(span path) const; // Like FindPath() but will only return the value if the leaf Value type // matches the given type. Will return nullptr otherwise. // Note: Prefer `FindPath()` for simple values. // // Note: If there is only one component in the path, use `FindKeyOfType()` // instead for slightly better performance. // // DEPRECATED: Use `Value::Dict::FindBoolByDottedPath()`, // `Value::Dict::FindIntByDottedPath()`, et cetera. Value* FindPathOfType(StringPiece path, Type type); const Value* FindPathOfType(StringPiece path, Type type) const; // Convenience accessors used when the expected type of a value is known. // Similar to FindKey() but accepts paths instead of keys. // // DEPRECATED: Use `Value::Dict::FindBoolByDottedPath()`, or // `Value::Dict::FindBool()` if the path only has one component, i.e. has no // dots. absl::optional FindBoolPath(StringPiece path) const; // DEPRECATED: Use `Value::Dict::FindIntByDottedPath()`, or // `Value::Dict::FindInt()` if the path only has one component, i.e. has no // dots. absl::optional FindIntPath(StringPiece path) const; // DEPRECATED: Use `Value::Dict::FindDoubleByDottedPath()`, or // `Value::Dict::FindDouble()` if the path only has one component, i.e. has no // dots. absl::optional FindDoublePath(StringPiece path) const; // DEPRECATED: Use `Value::Dict::FindStringByDottedPath()`, or // `Value::Dict::FindString()` if the path only has one component, i.e. has no // dots. const std::string* FindStringPath(StringPiece path) const; std::string* FindStringPath(StringPiece path); // DEPRECATED: Use `Value::Dict::FindBlobByDottedPath()`, or // `Value::Dict::FindBlob()` if the path only has one component, i.e. has no // dots. const BlobStorage* FindBlobPath(StringPiece path) const; // DEPRECATED: Use `Value::Dict::FindDictByDottedPath()`, or // `Value::Dict::FindDict()` if the path only has one component, i.e. has no // dots. Value* FindDictPath(StringPiece path); const Value* FindDictPath(StringPiece path) const; // DEPRECATED: Use `Value::Dict::FindListByDottedPath()`, or // `Value::Dict::FindList()` if the path only has one component, i.e. has no // dots. Value* FindListPath(StringPiece path); const Value* FindListPath(StringPiece path) const; // The following forms are deprecated too, use the ones that take the path // as a single StringPiece instead. // // DEPRECATED: These are not common, and there is no currently planned // replacement. Value* FindPathOfType(std::initializer_list path, Type type); Value* FindPathOfType(span path, Type type); const Value* FindPathOfType(std::initializer_list path, Type type) const; const Value* FindPathOfType(span path, Type type) const; // Sets the given path, expanding and creating dictionary keys as necessary. // // If the current value is not a dictionary, the function returns nullptr. If // path components do not exist, they will be created. If any but the last // components matches a value that is not a dictionary, the function will fail // (it will not overwrite the value) and return nullptr. The last path // component will be unconditionally overwritten if it exists, and created if // it doesn't. // // Note: If there is only one component in the path, use `SetKey()` instead. // Note: Using `SetPath()` might be more convenient and efficient. // // DEPRECATED: Use `Value::Dict::SetByDottedPath()`. Value* SetPath(StringPiece path, Value&& value); // These setters are more convenient and efficient than the corresponding // SetPath(...) call. // // DEPRECATED: Use `Value::Dict::SetByDottedPath()`. Value* SetBoolPath(StringPiece path, bool value); // DEPRECATED: Use `Value::Dict::SetByDottedPath()`. Value* SetIntPath(StringPiece path, int value); // DEPRECATED: Use `Value::Dict::SetByDottedPath()`. Value* SetDoublePath(StringPiece path, double value); // DEPRECATED: Use `Value::Dict::SetByDottedPath()`. Value* SetStringPath(StringPiece path, StringPiece value); // DEPRECATED: Use `Value::Dict::SetByDottedPath()`. Value* SetStringPath(StringPiece path, const char* value); // DEPRECATED: Use `Value::Dict::SetByDottedPath()`. Value* SetStringPath(StringPiece path, std::string&& value); // DEPRECATED: Use `Value::Dict::SetByDottedPath()`. Value* SetStringPath(StringPiece path, StringPiece16 value); // DEPRECATED: Use `Value::Dict::SetByDottedPath()`. Value* SetPath(std::initializer_list path, Value&& value); Value* SetPath(span path, Value&& value); // Tries to remove a Value at the given path. // // If the current value is not a dictionary or any path component does not // exist, this operation fails, leaves underlying Values untouched and returns // `false`. In case intermediate dictionaries become empty as a result of this // path removal, they will be removed as well. // Note: If there is only one component in the path, use `RemoveKey()` // instead. // // DEPRECATED: Use `Value::Dict::RemoveByDottedPath()`. bool RemovePath(StringPiece path); // Tries to extract a Value at the given path. // // If the current value is not a dictionary or any path component does not // exist, this operation fails, leaves underlying Values untouched and returns // nullopt. In case intermediate dictionaries become empty as a result of this // path removal, they will be removed as well. Returns the extracted value on // success. // Note: If there is only one component in the path, use `ExtractKey()` // instead. // // DEPRECATED: Use `Value::Dict::ExtractByDottedPath()`. absl::optional ExtractPath(StringPiece path); using dict_iterator_proxy = detail::dict_iterator_proxy; using const_dict_iterator_proxy = detail::const_dict_iterator_proxy; // `DictItems` returns a proxy object that exposes iterators to the underlying // dictionary. These are intended for iteration over all items in the // dictionary and are compatible with for-each loops and standard library // algorithms. // // Unlike with std::map, a range-for over the non-const version of // `DictItems()` will range over items of type // `pair`, so code of the form // for (auto kv : my_value.DictItems()) // Mutate(kv.second); // will actually alter `my_value` in place (if it isn't const). // // DEPRECATED: Use a range-based for loop over `base::Value::Dict` directly // instead. dict_iterator_proxy DictItems(); const_dict_iterator_proxy DictItems() const; // Transfers ownership of the underlying dict to the caller. Subsequent // calls to DictItems() will return an empty dict. // // DEPRECATED: prefer direct use of `base::Value::Dict` where possible, or // `std::move(value.GetDict())` otherwise. DeprecatedDictStorage TakeDictDeprecated() &&; // DEPRECATED: prefer `Value::Dict::size()`. size_t DictSize() const; // DEPRECATED: prefer `Value::Dict::empty()`. bool DictEmpty() const; // DEPRECATED: prefer `Value::Dict::clear()`. void DictClear(); // Merge `dictionary` into this value. This is done recursively, i.e. any // sub-dictionaries will be merged as well. In case of key collisions, the // passed in dictionary takes precedence and data already present will be // replaced. Values within `dictionary` are deep-copied, so `dictionary` may // be freed any time after this call. // Note: This requires that `type()` and `dictionary->type()` is // Type::DICT. // // DEPRECATED: prefer `Value::Dict::Merge()`. void MergeDictionary(const Value* dictionary); // These methods allow the convenient retrieval of the contents of the Value. // If the current object can be converted into the given type, the value is // returned through the `out_value` parameter and true is returned; // otherwise, false is returned and `out_value` is unchanged. // ListValue::From is the equivalent for std::unique_ptr conversions. // // DEPRECATED: prefer direct use `base::Value::List` where possible, or // `GetIfList()` otherwise. bool GetAsList(ListValue** out_value); bool GetAsList(const ListValue** out_value) const; // DictionaryValue::From is the equivalent for std::unique_ptr conversions. // // DEPRECATED: prefer direct use `base::Value::Dict` where possible, or // `GetIfDict()` otherwise. bool GetAsDictionary(DictionaryValue** out_value); bool GetAsDictionary(const DictionaryValue** out_value) const; // Note: Do not add more types. See the file-level comment above for why. // This creates a deep copy of the entire Value tree, and returns a pointer // to the copy. The caller gets ownership of the copy, of course. // Subclasses return their own type directly in their overrides; // this works because C++ supports covariant return types. // TODO(crbug.com/646113): Delete this and migrate callsites. // // DEPRECATED: prefer `Value::Clone()`. std::unique_ptr CreateDeepCopy() const; // Comparison operators so that Values can easily be used with standard // library algorithms and associative containers. BASE_EXPORT friend bool operator==(const Value& lhs, const Value& rhs); BASE_EXPORT friend bool operator!=(const Value& lhs, const Value& rhs); BASE_EXPORT friend bool operator<(const Value& lhs, const Value& rhs); BASE_EXPORT friend bool operator>(const Value& lhs, const Value& rhs); BASE_EXPORT friend bool operator<=(const Value& lhs, const Value& rhs); BASE_EXPORT friend bool operator>=(const Value& lhs, const Value& rhs); // Compares if two Value objects have equal contents. // DEPRECATED, use `operator==(const Value& lhs, const Value& rhs)` instead. // TODO(crbug.com/646113): Delete this and migrate callsites. // // DEPRECATED: prefer direct use of the equality operator instead. bool Equals(const Value* other) const; // Estimates dynamic memory usage. Requires tracing support // (enable_base_tracing gn flag), otherwise always returns 0. See // base/trace_event/memory_usage_estimator.h for more info. size_t EstimateMemoryUsage() const; // Serializes to a string for logging and debug purposes. std::string DebugString() const; #if BUILDFLAG(ENABLE_BASE_TRACING) // Write this object into a trace. void WriteIntoTrace(perfetto::TracedValue) const; #endif // BUILDFLAG(ENABLE_BASE_TRACING) template auto Visit(Visitor&& visitor) const { return absl::visit(std::forward(visitor), data_); } protected: // Checked convenience accessors for dict and list. const LegacyDictStorage& dict() const { return GetDict().storage_; } LegacyDictStorage& dict() { return GetDict().storage_; } const ListStorage& list() const { return GetList().storage_; } ListStorage& list() { return GetList().storage_; } // Internal constructors, allowing the simplify the implementation of Clone(). explicit Value(const LegacyDictStorage& storage); explicit Value(LegacyDictStorage&& storage) noexcept; private: // For access to DoubleStorage. friend class ValueView; // Special case for doubles, which are aligned to 8 bytes on some // 32-bit architectures. In this case, a simple declaration as a // double member would make the whole union 8 byte-aligned, which // would also force 4 bytes of wasted padding space before it in // the Value layout. // // To override this, store the value as an array of 32-bit integers, and // perform the appropriate bit casts when reading / writing to it. class DoubleStorage { public: explicit DoubleStorage(double v); DoubleStorage(const DoubleStorage&) = default; DoubleStorage& operator=(const DoubleStorage&) = default; // Provide an implicit conversion to double to simplify the use of visitors // with `Value::Visit()`. Otherwise, visitors would need a branch for // handling `DoubleStorage` like: // // value.Visit([] (const auto& member) { // using T = std::decay_t; // if constexpr (std::is_same_v) { // SomeFunction(double{member}); // } else { // SomeFunction(member); // } // }); operator double() const { return bit_cast(v_); } private: friend bool operator==(const DoubleStorage& lhs, const DoubleStorage& rhs) { return double{lhs} == double{rhs}; } friend bool operator!=(const DoubleStorage& lhs, const DoubleStorage& rhs) { return !(lhs == rhs); } friend bool operator<(const DoubleStorage& lhs, const DoubleStorage& rhs) { return double{lhs} < double{rhs}; } friend bool operator>(const DoubleStorage& lhs, const DoubleStorage& rhs) { return rhs < lhs; } friend bool operator<=(const DoubleStorage& lhs, const DoubleStorage& rhs) { return !(rhs < lhs); } friend bool operator>=(const DoubleStorage& lhs, const DoubleStorage& rhs) { return !(lhs < rhs); } alignas(4) std::array v_; }; // Internal constructors, allowing the simplify the implementation of Clone(). explicit Value(absl::monostate); explicit Value(DoubleStorage storage); friend class ValuesTest_SizeOfValue_Test; absl::variant data_; }; // DictionaryValue provides a key-value dictionary with (optional) "path" // parsing for recursive access; see the comment at the top of the file. Keys // are std::string's and should be UTF-8 encoded. // // DEPRECATED: prefer `Value::Dict`. class BASE_EXPORT DictionaryValue : public Value { public: // Returns `value` if it is a dictionary, nullptr otherwise. static std::unique_ptr From(std::unique_ptr value); DictionaryValue(); explicit DictionaryValue(const LegacyDictStorage& in_dict); explicit DictionaryValue(LegacyDictStorage&& in_dict) noexcept; // Returns true if the current dictionary has a value for the given key. // // DEPRECATED: prefer `Value::Dict::contains()`. bool HasKey(StringPiece key) const; // Sets the Value associated with the given path starting from this object. // A path has the form "" or "..[...]", where "." indexes // into the next DictionaryValue down. Obviously, "." can't be used // within a key, but there are no other restrictions on keys. // If the key at any step of the way doesn't exist, or exists but isn't // a DictionaryValue, a new DictionaryValue will be created and attached // to the path in that location. `in_value` must be non-null. // Returns a pointer to the inserted value. // // DEPRECATED: prefer `Value::Dict::Set()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::SetByDottedPath()` // otherwise. Value* Set(StringPiece path, std::unique_ptr in_value); // Convenience forms of Set(). These methods will replace any existing // value at that path, even if it has a different type. // // DEPRECATED: prefer `Value::Dict::Set()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::SetByDottedPath()` // otherwise. Value* SetBoolean(StringPiece path, bool in_value); // DEPRECATED: prefer `Value::Dict::Set()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::SetByDottedPath()` // otherwise. Value* SetInteger(StringPiece path, int in_value); // DEPRECATED: prefer `Value::Dict::Set()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::SetByDottedPath()` // otherwise. Value* SetDouble(StringPiece path, double in_value); // DEPRECATED: prefer `Value::Dict::Set()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::SetByDottedPath()` // otherwise. Value* SetString(StringPiece path, StringPiece in_value); // DEPRECATED: prefer `Value::Dict::Set()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::SetByDottedPath()` // otherwise. Value* SetString(StringPiece path, const std::u16string& in_value); // DEPRECATED: prefer `Value::Dict::Set()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::SetByDottedPath()` // otherwise. ListValue* SetList(StringPiece path, std::unique_ptr in_value); // Like Set(), but without special treatment of '.'. This allows e.g. URLs to // be used as paths. // // DEPRECATED: prefer `Value::Dict::Set()`. Value* SetWithoutPathExpansion(StringPiece key, std::unique_ptr in_value); // Gets the Value associated with the given path starting from this object. // A path has the form "" or "..[...]", where "." indexes // into the next DictionaryValue down. If the path can be resolved // successfully, the value for the last key in the path will be returned // through the `out_value` parameter, and the function will return true. // Otherwise, it will return false and `out_value` will be untouched. // Note that the dictionary always owns the value that's returned. // `out_value` is optional and will only be set if non-NULL. // // DEPRECATED: prefer `Value::Dict::Find()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::FindByDottedPath()` // otherwise. bool Get(StringPiece path, const Value** out_value) const; bool Get(StringPiece path, Value** out_value); // These are convenience forms of `Get()`. The value will be retrieved // and the return value will be true if the path is valid and the value at // the end of the path can be returned in the form specified. // `out_value` is optional and will only be set if non-NULL. // // DEPRECATED: prefer `Value::Dict::FindInt()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::FindIntByDottedPath()` // otherwise. bool GetInteger(StringPiece path, int* out_value) const; // DEPRECATED: prefer `Value::Dict::FindString()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::FindStringByDottedPath()` // otherwise. bool GetString(StringPiece path, std::string* out_value) const; bool GetString(StringPiece path, std::u16string* out_value) const; // DEPRECATED: prefer `Value::Dict::FindDict()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::FindDictByDottedPath()` // otherwise. bool GetDictionary(StringPiece path, const DictionaryValue** out_value) const; bool GetDictionary(StringPiece path, DictionaryValue** out_value); // DEPRECATED: prefer `Value::Dict::FindList()` (if the path only has one // component, i.e. has no dots), or `Value::Dict::FindListByDottedPath()` // otherwise. bool GetList(StringPiece path, const ListValue** out_value) const; bool GetList(StringPiece path, ListValue** out_value); // Like `Get()`, but without special treatment of '.'. This allows e.g. URLs // to be used as paths. // DEPRECATED, use `Value::FindDictKey(key)` instead. bool GetDictionaryWithoutPathExpansion( StringPiece key, const DictionaryValue** out_value) const; // DEPRECATED, use `Value::FindDictKey(key)` instead. bool GetDictionaryWithoutPathExpansion(StringPiece key, DictionaryValue** out_value); // DEPRECATED, use `Value::FindListKey(key)` instead. bool GetListWithoutPathExpansion(StringPiece key, const ListValue** out_value) const; // DEPRECATED, use `Value::FindListKey(key)` instead. bool GetListWithoutPathExpansion(StringPiece key, ListValue** out_value); // Makes a copy of `this` but doesn't include empty dictionaries and lists in // the copy. This never returns NULL, even if `this` itself is empty. std::unique_ptr DeepCopyWithoutEmptyChildren() const; // Swaps contents with the `other` dictionary. void Swap(DictionaryValue* other); // This class provides an iterator over both keys and values in the // dictionary. It can't be used to modify the dictionary. // // DEPRECATED: Use a range-based for loop over `base::Value::Dict` directly // instead. class BASE_EXPORT Iterator { public: explicit Iterator(const DictionaryValue& target); Iterator(const Iterator& other); ~Iterator(); bool IsAtEnd() const { return it_ == target_.DictItems().end(); } void Advance() { ++it_; } const std::string& key() const { return it_->first; } const Value& value() const { return it_->second; } private: const DictionaryValue& target_; detail::const_dict_iterator it_; }; // DEPRECATED, use `Value::Dict::Clone()` instead. // TODO(crbug.com/646113): Delete this and migrate callsites. DictionaryValue* DeepCopy() const; // DEPRECATED, use `Value::Dict::Clone()` instead. // TODO(crbug.com/646113): Delete this and migrate callsites. std::unique_ptr CreateDeepCopy() const; }; // This type of Value represents a list of other Value values. // // DEPRECATED: prefer `base::Value::List`. class BASE_EXPORT ListValue : public Value { public: using const_iterator = ListView::const_iterator; using iterator = ListView::iterator; // Returns `value` if it is a list, nullptr otherwise. static std::unique_ptr From(std::unique_ptr value); ListValue(); explicit ListValue(span in_list); explicit ListValue(ListStorage&& in_list) noexcept; // Convenience forms of `Get()`. Modifies `out_value` (and returns true) // only if the index is valid and the Value at that index can be returned // in the specified form. // `out_value` is optional and will only be set if non-NULL. // // DEPRECATED: prefer `Value::List::operator[]` + `GetIfDict()`. bool GetDictionary(size_t index, const DictionaryValue** out_value) const; bool GetDictionary(size_t index, DictionaryValue** out_value); // Appends a Value to the end of the list. // DEPRECATED: prefer `Value::List::Append()`. using Value::Append; // DEPRECATED: prefer `Value::List::Append()`. void Append(std::unique_ptr in_value); // Swaps contents with the `other` list. // // DEPRECATED: prefer `base::Value::List` + `std::swap()`. void Swap(ListValue* other); // Iteration: Use a range-based for loop over `base::Value::List` directly // instead. }; // Adapter so `Value::Dict` or `Value::List` can be directly passed to JSON // serialization methods without having to clone the contents and transfer // ownership of the clone to a `Value` wrapper object. // // Like `StringPiece` and `span`, this adapter does NOT retain ownership. Any // underlying object that is passed by reference (i.e. `std::string`, // `Value::BlobStorage`, `Value::Dict`, `Value::List`, or `Value`) MUST remain // live as long as there is a `ValueView` referencing it. // // While it might be nice to just use the `absl::variant` type directly, the // need to use `std::reference_wrapper` makes it clunky. `absl::variant` and // `std::reference_wrapper` both support implicit construction, but C++ only // allows at most one user-defined conversion in an implicit conversion // sequence. If this adapter and its implicit constructors did not exist, // callers would need to use `std::ref` or `std::cref` to pass `Value::Dict` or // `Value::List` to a function with a `ValueView` parameter. class BASE_EXPORT GSL_POINTER ValueView { public: ValueView(bool value) : data_view_(value) {} ValueView(int value) : data_view_(value) {} ValueView(double value) : data_view_(absl::in_place_type_t(), value) {} ValueView(const std::string& value) : data_view_(value) {} ValueView(const Value::BlobStorage& value) : data_view_(value) {} ValueView(const Value::Dict& value) : data_view_(value) {} ValueView(const Value::List& value) : data_view_(value) {} ValueView(const Value& value); template auto Visit(Visitor&& visitor) const { return absl::visit(std::forward(visitor), data_view_); } private: using ViewType = absl::variant, std::reference_wrapper, std::reference_wrapper, std::reference_wrapper>; ViewType data_view_; }; // This interface is implemented by classes that know how to serialize // Value objects. class BASE_EXPORT ValueSerializer { public: virtual ~ValueSerializer(); virtual bool Serialize(ValueView root) = 0; }; // This interface is implemented by classes that know how to deserialize Value // objects. class BASE_EXPORT ValueDeserializer { public: virtual ~ValueDeserializer(); // This method deserializes the subclass-specific format into a Value object. // If the return value is non-NULL, the caller takes ownership of returned // Value. // // If the return value is nullptr, and if `error_code` is non-nullptr, // `*error_code` will be set to an integer value representing the underlying // error. See "enum ErrorCode" below for more detail about the integer value. // // If `error_message` is non-nullptr, it will be filled in with a formatted // error message including the location of the error if appropriate. virtual std::unique_ptr Deserialize(int* error_code, std::string* error_message) = 0; // The integer-valued error codes form four groups: // - The value 0 means no error. // - Values between 1 and 999 inclusive mean an error in the data (i.e. // content). The bytes being deserialized are not in the right format. // - Values 1000 and above mean an error in the metadata (i.e. context). The // file could not be read, the network is down, etc. // - Negative values are reserved. // // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. enum ErrorCode { kErrorCodeNoError = 0, // kErrorCodeInvalidFormat is a generic error code for "the data is not in // the right format". Subclasses of ValueDeserializer may return other // values for more specific errors. kErrorCodeInvalidFormat = 1, // kErrorCodeFirstMetadataError is the minimum value (inclusive) of the // range of metadata errors. kErrorCodeFirstMetadataError = 1000, }; // The `error_code` argument can be one of the ErrorCode values, but it is // not restricted to only being 0, 1 or 1000. Subclasses of ValueDeserializer // can define their own error code values. static inline bool ErrorCodeIsDataError(int error_code) { return (kErrorCodeInvalidFormat <= error_code) && (error_code < kErrorCodeFirstMetadataError); } }; // Stream operator so Values can be pretty printed by gtest. BASE_EXPORT std::ostream& operator<<(std::ostream& out, const Value& value); BASE_EXPORT std::ostream& operator<<(std::ostream& out, const Value::Dict& dict); BASE_EXPORT std::ostream& operator<<(std::ostream& out, const Value::List& list); // Hints for DictionaryValue and ListValue; otherwise, gtest tends to prefer the // default template implementation over an upcast to Value. BASE_EXPORT inline std::ostream& operator<<(std::ostream& out, const DictionaryValue& value) { return out << static_cast(value); } BASE_EXPORT inline std::ostream& operator<<(std::ostream& out, const ListValue& value) { return out << static_cast(value); } // Stream operator so that enum class Types can be used in log statements. BASE_EXPORT std::ostream& operator<<(std::ostream& out, const Value::Type& type); } // namespace base #endif // BASE_VALUES_H_