blob: 315df7dbe1e3995f6881cba2b17509a8fbf56cb3 [file] [log] [blame]
Andrew Top0d1858f2019-05-15 22:01:47 -07001// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_THREADING_SEQUENCE_LOCAL_STORAGE_SLOT_H_
6#define BASE_THREADING_SEQUENCE_LOCAL_STORAGE_SLOT_H_
7
8#include <memory>
9#include <utility>
10
11#include "base/base_export.h"
12#include "base/threading/sequence_local_storage_map.h"
13
14namespace base {
15
16namespace internal {
17BASE_EXPORT int GetNextSequenceLocalStorageSlotNumber();
18}
19
20// SequenceLocalStorageSlot allows arbitrary values to be stored and retrieved
21// from a sequence. Values are deleted when the sequence is deleted.
22//
23// Example usage:
24//
25// namespace {
26// base::LazyInstance<SequenceLocalStorageSlot<int>> sls_value;
27// }
28//
29// void Read() {
30// int value = sls_value.Get().Get();
31// ...
32// }
33//
34// void Write() {
35// sls_value.Get().Set(42);
36// }
37//
38// void PostTasks() {
39// // Since Read() runs on the same sequence as Write(), it
40// // will read the value "42". A Read() running on a different
41// // sequence would not see that value.
42// scoped_refptr<base::SequencedTaskRunner> task_runner = ...;
43// task_runner->PostTask(FROM_HERE, base::BindOnce(&Write));
44// task_runner->PostTask(FROM_HERE, base::BindOnce(&Read));
45// }
46//
47// SequenceLocalStorageSlot must be used within the scope of a
48// ScopedSetSequenceLocalStorageMapForCurrentThread object.
49// Note: this is true on all TaskScheduler workers and on threads bound to a
50// MessageLoop.
51template <typename T, typename Deleter = std::default_delete<T>>
52class SequenceLocalStorageSlot {
53 public:
54 SequenceLocalStorageSlot()
55 : slot_id_(internal::GetNextSequenceLocalStorageSlotNumber()) {}
56 ~SequenceLocalStorageSlot() = default;
57
58 // Get the sequence-local value stored in this slot. Returns a
59 // default-constructed value if no value was previously set.
60 T& Get() {
61 void* value =
62 internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_);
63
64 // Sets and returns a default-constructed value if no value was previously
65 // set.
66 if (!value) {
67 Set(T());
68 return Get();
69 }
70 return *(static_cast<T*>(value));
71 }
72
73 // Set this slot's sequence-local value to |value|.
74 // Note that if T is expensive to copy, it may be more appropriate to instead
75 // store a std::unique_ptr<T>. This is enforced by the
76 // DISALLOW_COPY_AND_ASSIGN style rather than directly by this class however.
77 void Set(T value) {
78 // Allocates the |value| with new rather than std::make_unique.
79 // Since SequenceLocalStorageMap needs to store values of various types
80 // within the same map, the type of value_destructor_pair.value is void*
81 // (std::unique_ptr<void> is invalid). Memory is freed by calling
82 // |value_destructor_pair.destructor| in the destructor of
83 // ValueDestructorPair which is invoked when the value is overwritten by
84 // another call to SequenceLocalStorageMap::Set or when the
85 // SequenceLocalStorageMap is deleted.
86 T* value_ptr = new T(std::move(value));
87
88 internal::SequenceLocalStorageMap::ValueDestructorPair::DestructorFunc*
89 destructor = [](void* ptr) { Deleter()(static_cast<T*>(ptr)); };
90
91 internal::SequenceLocalStorageMap::ValueDestructorPair
92 value_destructor_pair(value_ptr, destructor);
93
94 internal::SequenceLocalStorageMap::GetForCurrentThread().Set(
95 slot_id_, std::move(value_destructor_pair));
96 }
97
98 private:
99 // |slot_id_| is used as a key in SequenceLocalStorageMap
100 const int slot_id_;
101 DISALLOW_COPY_AND_ASSIGN(SequenceLocalStorageSlot);
102};
103
104} // namespace base
105#endif // BASE_THREADING_SEQUENCE_LOCAL_STORAGE_SLOT_H_