| // Copyright 2017 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_THREADING_SEQUENCE_LOCAL_STORAGE_SLOT_H_ |
| #define BASE_THREADING_SEQUENCE_LOCAL_STORAGE_SLOT_H_ |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/base_export.h" |
| #include "base/threading/sequence_local_storage_map.h" |
| |
| namespace base { |
| |
| namespace internal { |
| BASE_EXPORT int GetNextSequenceLocalStorageSlotNumber(); |
| } |
| |
| // SequenceLocalStorageSlot allows arbitrary values to be stored and retrieved |
| // from a sequence. Values are deleted when the sequence is deleted. |
| // |
| // Example usage: |
| // |
| // namespace { |
| // base::LazyInstance<SequenceLocalStorageSlot<int>> sls_value; |
| // } |
| // |
| // void Read() { |
| // int value = sls_value.Get().Get(); |
| // ... |
| // } |
| // |
| // void Write() { |
| // sls_value.Get().Set(42); |
| // } |
| // |
| // void PostTasks() { |
| // // Since Read() runs on the same sequence as Write(), it |
| // // will read the value "42". A Read() running on a different |
| // // sequence would not see that value. |
| // scoped_refptr<base::SequencedTaskRunner> task_runner = ...; |
| // task_runner->PostTask(FROM_HERE, base::BindOnce(&Write)); |
| // task_runner->PostTask(FROM_HERE, base::BindOnce(&Read)); |
| // } |
| // |
| // SequenceLocalStorageSlot must be used within the scope of a |
| // ScopedSetSequenceLocalStorageMapForCurrentThread object. |
| // Note: this is true on all TaskScheduler workers and on threads bound to a |
| // MessageLoop. |
| template <typename T, typename Deleter = std::default_delete<T>> |
| class SequenceLocalStorageSlot { |
| public: |
| SequenceLocalStorageSlot() |
| : slot_id_(internal::GetNextSequenceLocalStorageSlotNumber()) {} |
| ~SequenceLocalStorageSlot() = default; |
| |
| // Get the sequence-local value stored in this slot. Returns a |
| // default-constructed value if no value was previously set. |
| T& Get() { |
| void* value = |
| internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_); |
| |
| // Sets and returns a default-constructed value if no value was previously |
| // set. |
| if (!value) { |
| Set(T()); |
| return Get(); |
| } |
| return *(static_cast<T*>(value)); |
| } |
| |
| // Set this slot's sequence-local value to |value|. |
| // Note that if T is expensive to copy, it may be more appropriate to instead |
| // store a std::unique_ptr<T>. This is enforced by the |
| // DISALLOW_COPY_AND_ASSIGN style rather than directly by this class however. |
| void Set(T value) { |
| // Allocates the |value| with new rather than std::make_unique. |
| // Since SequenceLocalStorageMap needs to store values of various types |
| // within the same map, the type of value_destructor_pair.value is void* |
| // (std::unique_ptr<void> is invalid). Memory is freed by calling |
| // |value_destructor_pair.destructor| in the destructor of |
| // ValueDestructorPair which is invoked when the value is overwritten by |
| // another call to SequenceLocalStorageMap::Set or when the |
| // SequenceLocalStorageMap is deleted. |
| T* value_ptr = new T(std::move(value)); |
| |
| internal::SequenceLocalStorageMap::ValueDestructorPair::DestructorFunc* |
| destructor = [](void* ptr) { Deleter()(static_cast<T*>(ptr)); }; |
| |
| internal::SequenceLocalStorageMap::ValueDestructorPair |
| value_destructor_pair(value_ptr, destructor); |
| |
| internal::SequenceLocalStorageMap::GetForCurrentThread().Set( |
| slot_id_, std::move(value_destructor_pair)); |
| } |
| |
| private: |
| // |slot_id_| is used as a key in SequenceLocalStorageMap |
| const int slot_id_; |
| DISALLOW_COPY_AND_ASSIGN(SequenceLocalStorageSlot); |
| }; |
| |
| } // namespace base |
| #endif // BASE_THREADING_SEQUENCE_LOCAL_STORAGE_SLOT_H_ |