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