// Copyright 2017 The Chromium Authors // 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 <type_traits> #include <utility> #include "base/base_export.h" #include "base/threading/sequence_local_storage_map.h" #include "third_party/abseil-cpp/absl/meta/type_traits.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: // // int& GetSequenceLocalStorage() // static SequenceLocalStorageSlot<int> sls_value; // return sls_value->GetOrCreateValue(); // } // // void Read() { // int value = GetSequenceLocalStorage(); // ... // } // // void Write() { // GetSequenceLocalStorage() = 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 ThreadPool workers and on threads bound to a // MessageLoop. // SequenceLocalStorageSlot is implemented by either [Generic/Small] // variants depending on the type. SequenceLocalStorageSlot itself // doesn't support forward declared types and thus the variant // [Generic/Small] needs to be specified explicitly. // Generic implementation for SequenceLocalStorageSlot. template <typename T, typename Deleter = std::default_delete<T>> class GenericSequenceLocalStorageSlot { public: GenericSequenceLocalStorageSlot() : … { … } GenericSequenceLocalStorageSlot(const GenericSequenceLocalStorageSlot&) = delete; GenericSequenceLocalStorageSlot& operator=( const GenericSequenceLocalStorageSlot&) = delete; ~GenericSequenceLocalStorageSlot() = default; explicit operator bool() const { return internal::SequenceLocalStorageMap::GetForCurrentThread().Has( slot_id_); } // Default-constructs the value for the current sequence if not // already constructed. Then, returns the value. T& GetOrCreateValue() { … } // Returns a pointer to the value for the current sequence. May be // nullptr if the value was not constructed on the current sequence. T* GetValuePointer() { … } const T* GetValuePointer() const { … } T* operator->() { … } const T* operator->() const { … } T& operator*() { … } const T& operator*() const { … } void reset() { … } // Constructs this slot's sequence-local value with |args...| and returns a // pointer to the created object. template <class... Args> T& emplace(Args&&... args) { … } private: // Takes ownership of |value_ptr|. void Adopt(T* value_ptr) { … } // |slot_id_| is used as a key in SequenceLocalStorageMap const int slot_id_; }; // Implementation for SequenceLocalStorageSlot optimized for small and trivial // objects. template <class T> class SmallSequenceLocalStorageSlot { … }; template <typename T, typename Deleter = std::default_delete<T>, bool IsSmall = sizeof(T) <= sizeof(void*) && absl::is_trivially_relocatable<T>()> struct SequenceLocalStorageSlot; SequenceLocalStorageSlot<T, Deleter, false>; SequenceLocalStorageSlot<T, std::default_delete<T>, true>; } // namespace base #endif // BASE_THREADING_SEQUENCE_LOCAL_STORAGE_SLOT_H_