1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/supports_user_data.h"
6
7 #include "base/feature_list.h"
8 #include "base/features.h"
9 #include "base/sequence_checker.h"
10
11 namespace base {
12
Clone()13 std::unique_ptr<SupportsUserData::Data> SupportsUserData::Data::Clone() {
14 return nullptr;
15 }
16
SupportsUserData()17 SupportsUserData::SupportsUserData()
18 : user_data_(FeatureList::IsEnabled(features::kSupportsUserDataFlatHashMap)
19 ? MapVariants(FlatDataMap())
20 : MapVariants(DataMap())) {
21 // Harmless to construct on a different execution sequence to subsequent
22 // usage.
23 DETACH_FROM_SEQUENCE(sequence_checker_);
24 }
25
26 SupportsUserData::SupportsUserData(SupportsUserData&&) = default;
27 SupportsUserData& SupportsUserData::operator=(SupportsUserData&&) = default;
28
GetUserData(const void * key) const29 SupportsUserData::Data* SupportsUserData::GetUserData(const void* key) const {
30 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
31 // Avoid null keys; they are too vulnerable to collision.
32 DCHECK(key);
33 return absl::visit(
34 [key](const auto& map) -> Data* {
35 auto found = map.find(key);
36 if (found != map.end()) {
37 return found->second.get();
38 }
39 return nullptr;
40 },
41 user_data_);
42 }
43
TakeUserData(const void * key)44 std::unique_ptr<SupportsUserData::Data> SupportsUserData::TakeUserData(
45 const void* key) {
46 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
47 // Null keys are too vulnerable to collision.
48 CHECK(key);
49 return absl::visit(
50 [key](auto& map) -> std::unique_ptr<SupportsUserData::Data> {
51 auto found = map.find(key);
52 if (found != map.end()) {
53 std::unique_ptr<SupportsUserData::Data> deowned;
54 deowned.swap(found->second);
55 map.erase(key);
56 return deowned;
57 }
58 return nullptr;
59 },
60 user_data_);
61 }
62
SetUserData(const void * key,std::unique_ptr<Data> data)63 void SupportsUserData::SetUserData(const void* key,
64 std::unique_ptr<Data> data) {
65 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
66 // Avoid null keys; they are too vulnerable to collision.
67 DCHECK(key);
68 if (data.get()) {
69 absl::visit([key, &data](auto& map) { map[key] = std::move(data); },
70 user_data_);
71 } else {
72 RemoveUserData(key);
73 }
74 }
75
RemoveUserData(const void * key)76 void SupportsUserData::RemoveUserData(const void* key) {
77 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
78 absl::visit(
79 [key](auto& map) {
80 auto it = map.find(key);
81 if (it != map.end()) {
82 // Remove the entry from the map before deleting `owned_data` to avoid
83 // reentrancy issues when `owned_data` owns `this`. Otherwise:
84 //
85 // 1. `RemoveUserData()` calls `erase()`.
86 // 2. `erase()` deletes `owned_data`.
87 // 3. `owned_data` deletes `this`.
88 //
89 // At this point, `erase()` is still on the stack even though the
90 // backing map (owned by `this`) has already been destroyed, and it
91 // may simply crash, cause a use-after-free, or any other number of
92 // interesting things.
93 auto owned_data = std::move(it->second);
94 map.erase(it);
95 }
96 },
97 user_data_);
98 }
99
DetachFromSequence()100 void SupportsUserData::DetachFromSequence() {
101 DETACH_FROM_SEQUENCE(sequence_checker_);
102 }
103
CloneDataFrom(const SupportsUserData & other)104 void SupportsUserData::CloneDataFrom(const SupportsUserData& other) {
105 absl::visit(
106 [this](const auto& other_map) {
107 for (const auto& data_pair : other_map) {
108 auto cloned_data = data_pair.second->Clone();
109 if (cloned_data) {
110 SetUserData(data_pair.first, std::move(cloned_data));
111 }
112 }
113 },
114 other.user_data_);
115 }
116
~SupportsUserData()117 SupportsUserData::~SupportsUserData() {
118 if (!absl::visit([](const auto& map) { return map.empty(); }, user_data_)) {
119 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
120 }
121 MapVariants local_user_data;
122 user_data_.swap(local_user_data);
123 // Now this->user_data_ is empty, and any destructors called transitively from
124 // the destruction of |local_user_data| will see it that way instead of
125 // examining a being-destroyed object.
126 }
127
ClearAllUserData()128 void SupportsUserData::ClearAllUserData() {
129 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
130 absl::visit([](auto& map) { map.clear(); }, user_data_);
131 }
132
133 } // namespace base
134