#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();
}
template <typename T, typename Deleter = std::default_delete<T>>
class GenericSequenceLocalStorageSlot {
public:
GenericSequenceLocalStorageSlot()
: slot_id_(internal::GetNextSequenceLocalStorageSlotNumber()) {}
GenericSequenceLocalStorageSlot(const GenericSequenceLocalStorageSlot&) =
delete;
GenericSequenceLocalStorageSlot& operator=(
const GenericSequenceLocalStorageSlot&) = delete;
~GenericSequenceLocalStorageSlot() = default;
explicit operator bool() const {
return internal::SequenceLocalStorageMap::GetForCurrentThread().Has(
slot_id_);
}
T& GetOrCreateValue() {
auto* slot =
internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_);
if (!slot) {
return emplace();
}
return slot->external_value.value_as<T>();
}
T* GetValuePointer() {
auto* value =
internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_);
if (value) {
return std::addressof(value->external_value.value_as<T>());
}
return nullptr;
}
const T* GetValuePointer() const {
return const_cast<GenericSequenceLocalStorageSlot*>(this)
->GetValuePointer();
}
T* operator->() { return GetValuePointer(); }
const T* operator->() const { return GetValuePointer(); }
T& operator*() { return *GetValuePointer(); }
const T& operator*() const { return *GetValuePointer(); }
void reset() {
internal::SequenceLocalStorageMap::GetForCurrentThread().Reset(slot_id_);
}
template <class... Args>
T& emplace(Args&&... args) {
T* value_ptr = new T(std::forward<Args>(args)...);
Adopt(value_ptr);
return *value_ptr;
}
private:
void Adopt(T* value_ptr) {
internal::SequenceLocalStorageMap::ExternalValue value;
value.emplace(value_ptr);
internal::SequenceLocalStorageMap::ValueDestructorPair
value_destructor_pair(
std::move(value),
internal::SequenceLocalStorageMap::MakeExternalDestructor<
T, Deleter>());
internal::SequenceLocalStorageMap::GetForCurrentThread().Set(
slot_id_, std::move(value_destructor_pair));
}
const int slot_id_;
};
template <class T>
class SmallSequenceLocalStorageSlot {
public:
SmallSequenceLocalStorageSlot()
: slot_id_(internal::GetNextSequenceLocalStorageSlotNumber()) {}
SmallSequenceLocalStorageSlot(const SmallSequenceLocalStorageSlot&) = delete;
SmallSequenceLocalStorageSlot& operator=(
const SmallSequenceLocalStorageSlot&) = delete;
~SmallSequenceLocalStorageSlot() = default;
explicit operator bool() const {
return internal::SequenceLocalStorageMap::GetForCurrentThread().Has(
slot_id_);
}
T& GetOrCreateValue() {
auto* slot =
internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_);
if (!slot) {
return emplace();
}
return slot->inline_value.value_as<T>();
}
T* GetValuePointer() {
auto* slot =
internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_);
if (!slot) {
return nullptr;
}
return &slot->inline_value.value_as<T>();
}
const T* GetValuePointer() const {
return const_cast<SmallSequenceLocalStorageSlot*>(this)->GetValuePointer();
}
T* operator->() { return GetValuePointer(); }
const T* operator->() const { return GetValuePointer(); }
T& operator*() { return *GetValuePointer(); }
const T& operator*() const { return *GetValuePointer(); }
void reset() {
internal::SequenceLocalStorageMap::GetForCurrentThread().Reset(slot_id_);
}
template <class... Args>
T& emplace(Args&&... args) {
internal::SequenceLocalStorageMap::InlineValue value;
value.emplace<T>(std::forward<Args>(args)...);
internal::SequenceLocalStorageMap::ValueDestructorPair
value_destructor_pair(
std::move(value),
internal::SequenceLocalStorageMap::MakeInlineDestructor<T>());
return internal::SequenceLocalStorageMap::GetForCurrentThread()
.Set(slot_id_, std::move(value_destructor_pair))
->inline_value.value_as<T>();
}
private:
const int slot_id_;
};
template <typename T,
typename Deleter = std::default_delete<T>,
bool IsSmall =
sizeof(T) <= sizeof(void*) && absl::is_trivially_relocatable<T>()>
struct SequenceLocalStorageSlot;
template <typename T, typename Deleter>
struct SequenceLocalStorageSlot<T, Deleter, false>
: GenericSequenceLocalStorageSlot<T, Deleter> {};
template <typename T>
struct SequenceLocalStorageSlot<T, std::default_delete<T>, true>
: SmallSequenceLocalStorageSlot<T> {};
}
#endif