// 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_