| // 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. | 
 |  | 
 | #include "base/threading/sequence_local_storage_map.h" | 
 |  | 
 | #include <utility> | 
 |  | 
 | #include "base/lazy_instance.h" | 
 | #include "base/logging.h" | 
 | #include "base/threading/thread_local.h" | 
 |  | 
 | namespace base { | 
 | namespace internal { | 
 |  | 
 | namespace { | 
 | LazyInstance<ThreadLocalPointer<SequenceLocalStorageMap>>::Leaky | 
 |     tls_current_sequence_local_storage = LAZY_INSTANCE_INITIALIZER; | 
 | }  // namespace | 
 |  | 
 | SequenceLocalStorageMap::SequenceLocalStorageMap() = default; | 
 |  | 
 | SequenceLocalStorageMap::~SequenceLocalStorageMap() = default; | 
 |  | 
 | ScopedSetSequenceLocalStorageMapForCurrentThread:: | 
 |     ScopedSetSequenceLocalStorageMapForCurrentThread( | 
 |         SequenceLocalStorageMap* sequence_local_storage) { | 
 |   DCHECK(!tls_current_sequence_local_storage.Get().Get()); | 
 |   tls_current_sequence_local_storage.Get().Set(sequence_local_storage); | 
 | } | 
 |  | 
 | ScopedSetSequenceLocalStorageMapForCurrentThread:: | 
 |     ~ScopedSetSequenceLocalStorageMapForCurrentThread() { | 
 |   tls_current_sequence_local_storage.Get().Set(nullptr); | 
 | } | 
 |  | 
 | SequenceLocalStorageMap& SequenceLocalStorageMap::GetForCurrentThread() { | 
 |   SequenceLocalStorageMap* current_sequence_local_storage = | 
 |       tls_current_sequence_local_storage.Get().Get(); | 
 |  | 
 |   DCHECK(current_sequence_local_storage) | 
 |       << "SequenceLocalStorageSlot cannot be used because no " | 
 |          "SequenceLocalStorageMap was stored in TLS. Use " | 
 |          "ScopedSetSequenceLocalStorageMapForCurrentThread to store a " | 
 |          "SequenceLocalStorageMap object in TLS."; | 
 |  | 
 |   return *current_sequence_local_storage; | 
 | } | 
 |  | 
 | void* SequenceLocalStorageMap::Get(int slot_id) { | 
 |   const auto it = sls_map_.find(slot_id); | 
 |   if (it == sls_map_.end()) | 
 |     return nullptr; | 
 |   return it->second.value(); | 
 | } | 
 |  | 
 | void SequenceLocalStorageMap::Set( | 
 |     int slot_id, | 
 |     SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair) { | 
 |   auto it = sls_map_.find(slot_id); | 
 |  | 
 |   if (it == sls_map_.end()) | 
 |     sls_map_.emplace(slot_id, std::move(value_destructor_pair)); | 
 |   else | 
 |     it->second = std::move(value_destructor_pair); | 
 |  | 
 |   // The maximum number of entries in the map is 256. This can be adjusted, but | 
 |   // will require reviewing the choice of data structure for the map. | 
 |   DCHECK_LE(sls_map_.size(), 256U); | 
 | } | 
 |  | 
 | SequenceLocalStorageMap::ValueDestructorPair::ValueDestructorPair( | 
 |     void* value, | 
 |     DestructorFunc* destructor) | 
 |     : value_(value), destructor_(destructor) {} | 
 |  | 
 | SequenceLocalStorageMap::ValueDestructorPair::~ValueDestructorPair() { | 
 |   if (value_) | 
 |     destructor_(value_); | 
 | } | 
 |  | 
 | SequenceLocalStorageMap::ValueDestructorPair::ValueDestructorPair( | 
 |     ValueDestructorPair&& value_destructor_pair) | 
 |     : value_(value_destructor_pair.value_), | 
 |       destructor_(value_destructor_pair.destructor_) { | 
 |   value_destructor_pair.value_ = nullptr; | 
 | } | 
 |  | 
 | SequenceLocalStorageMap::ValueDestructorPair& | 
 | SequenceLocalStorageMap::ValueDestructorPair::operator=( | 
 |     ValueDestructorPair&& value_destructor_pair) { | 
 |   // Destroy |value_| before overwriting it with a new value. | 
 |   if (value_) | 
 |     destructor_(value_); | 
 |  | 
 |   value_ = value_destructor_pair.value_; | 
 |   destructor_ = value_destructor_pair.destructor_; | 
 |  | 
 |   value_destructor_pair.value_ = nullptr; | 
 |  | 
 |   return *this; | 
 | } | 
 |  | 
 | }  // namespace internal | 
 | }  // namespace base |