// Copyright (c) 2016 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. // unique_ptr-style pointer that stores values that may be from an arena. Takes // up the same storage as the platform's native pointer type. Takes ownership // of the value it's constructed with; if holding a value in an arena, and the // type has a non-trivial destructor, the arena must outlive the // QuicArenaScopedPtr. Does not support array overloads. #ifndef NET_QUIC_QUIC_ARENA_SCOPED_PTR_H_ #define NET_QUIC_QUIC_ARENA_SCOPED_PTR_H_ #include // for uintptr_t #include "base/logging.h" #include "base/macros.h" #include "net/quic/quic_utils.h" namespace net { template class QuicArenaScopedPtr { static_assert(QUIC_ALIGN_OF(T*) > 1, "QuicArenaScopedPtr can only store objects that are aligned to " "greater than 1 byte."); public: // Constructs an empty QuicArenaScopedPtr. QuicArenaScopedPtr(); // Constructs a QuicArenaScopedPtr referencing the heap-allocated memory // provided. explicit QuicArenaScopedPtr(T* value); template QuicArenaScopedPtr(QuicArenaScopedPtr&& other); // NOLINT template QuicArenaScopedPtr& operator=(QuicArenaScopedPtr&& other); ~QuicArenaScopedPtr(); // Returns a pointer to the value. T* get() const; // Returns a reference to the value. T& operator*() const; // Returns a pointer to the value. T* operator->() const; // Swaps the value of this pointer with |other|. void swap(QuicArenaScopedPtr& other); // Resets the held value to |value|. void reset(T* value = nullptr); // Returns true if |this| came from an arena. Primarily exposed for testing // and assertions. bool is_from_arena(); private: // Friends with other derived types of QuicArenaScopedPtr, to support the // derived-types case. template friend class QuicArenaScopedPtr; // Also befriend all known arenas, only to prevent misuse. template friend class QuicOneBlockArena; // Tag to denote that a QuicArenaScopedPtr is being explicitly created by an // arena. enum class ConstructFrom { kHeap, kArena }; // Constructs a QuicArenaScopedPtr with the given representation. QuicArenaScopedPtr(void* value, ConstructFrom from); // Low-order bits of value_ that determine if the pointer came from an arena. static const uintptr_t kFromArenaMask = 0x1; // Every platform we care about has at least 4B aligned integers, so store the // is_from_arena bit in the least significant bit. void* value_; DISALLOW_COPY_AND_ASSIGN(QuicArenaScopedPtr); }; template bool operator==(const QuicArenaScopedPtr& left, const QuicArenaScopedPtr& right) { return left.get() == right.get(); } template bool operator!=(const QuicArenaScopedPtr& left, const QuicArenaScopedPtr& right) { return left.get() != right.get(); } template bool operator==(std::nullptr_t, const QuicArenaScopedPtr& right) { return nullptr == right.get(); } template bool operator!=(std::nullptr_t, const QuicArenaScopedPtr& right) { return nullptr != right.get(); } template bool operator==(const QuicArenaScopedPtr& left, std::nullptr_t) { return left.get() == nullptr; } template bool operator!=(const QuicArenaScopedPtr& left, std::nullptr_t) { return left.get() != nullptr; } template QuicArenaScopedPtr::QuicArenaScopedPtr() : value_(nullptr) {} template QuicArenaScopedPtr::QuicArenaScopedPtr(T* value) : QuicArenaScopedPtr(value, ConstructFrom::kHeap) {} template template QuicArenaScopedPtr::QuicArenaScopedPtr(QuicArenaScopedPtr&& other) : value_(other.value_) { static_assert( std::is_base_of::value || std::is_same::value, "Cannot construct QuicArenaScopedPtr; type is not derived or same."); other.value_ = nullptr; } template template QuicArenaScopedPtr& QuicArenaScopedPtr::operator=( QuicArenaScopedPtr&& other) { static_assert( std::is_base_of::value || std::is_same::value, "Cannot assign QuicArenaScopedPtr; type is not derived or same."); swap(other); return *this; } template QuicArenaScopedPtr::~QuicArenaScopedPtr() { reset(); } template T* QuicArenaScopedPtr::get() const { return reinterpret_cast(reinterpret_cast(value_) & ~kFromArenaMask); } template T& QuicArenaScopedPtr::operator*() const { return *get(); } template T* QuicArenaScopedPtr::operator->() const { return get(); } template void QuicArenaScopedPtr::swap(QuicArenaScopedPtr& other) { using std::swap; swap(value_, other.value_); } template bool QuicArenaScopedPtr::is_from_arena() { return (reinterpret_cast(value_) & kFromArenaMask) != 0; } template void QuicArenaScopedPtr::reset(T* value) { if (value_ != nullptr) { if (is_from_arena()) { // Manually invoke the destructor. get()->~T(); } else { delete get(); } } DCHECK_EQ(0u, reinterpret_cast(value) & kFromArenaMask); value_ = value; } template QuicArenaScopedPtr::QuicArenaScopedPtr(void* value, ConstructFrom from_arena) : value_(value) { DCHECK_EQ(0u, reinterpret_cast(value_) & kFromArenaMask); switch (from_arena) { case ConstructFrom::kHeap: break; case ConstructFrom::kArena: value_ = reinterpret_cast(reinterpret_cast(value_) | QuicArenaScopedPtr::kFromArenaMask); break; } } } // namespace net #endif // NET_QUIC_QUIC_ARENA_SCOPED_PTR_H_