Project import generated by Copybara. PiperOrigin-RevId: 237361882 Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/quic_arena_scoped_ptr.h b/quic/core/quic_arena_scoped_ptr.h new file mode 100644 index 0000000..b719185 --- /dev/null +++ b/quic/core/quic_arena_scoped_ptr.h
@@ -0,0 +1,209 @@ +// 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 QUICHE_QUIC_CORE_QUIC_ARENA_SCOPED_PTR_H_ +#define QUICHE_QUIC_CORE_QUIC_ARENA_SCOPED_PTR_H_ + +#include <cstdint> // for uintptr_t + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +template <typename T> +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 <typename U> + QuicArenaScopedPtr(QuicArenaScopedPtr<U>&& other); // NOLINT + template <typename U> + QuicArenaScopedPtr& operator=(QuicArenaScopedPtr<U>&& 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 <typename U> + friend class QuicArenaScopedPtr; + // Also befriend all known arenas, only to prevent misuse. + template <uint32_t ArenaSize> + 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); + QuicArenaScopedPtr(const QuicArenaScopedPtr&) = delete; + QuicArenaScopedPtr& operator=(const QuicArenaScopedPtr&) = delete; + + // 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_; +}; + +template <typename T> +bool operator==(const QuicArenaScopedPtr<T>& left, + const QuicArenaScopedPtr<T>& right) { + return left.get() == right.get(); +} + +template <typename T> +bool operator!=(const QuicArenaScopedPtr<T>& left, + const QuicArenaScopedPtr<T>& right) { + return left.get() != right.get(); +} + +template <typename T> +bool operator==(std::nullptr_t, const QuicArenaScopedPtr<T>& right) { + return nullptr == right.get(); +} + +template <typename T> +bool operator!=(std::nullptr_t, const QuicArenaScopedPtr<T>& right) { + return nullptr != right.get(); +} + +template <typename T> +bool operator==(const QuicArenaScopedPtr<T>& left, std::nullptr_t) { + return left.get() == nullptr; +} + +template <typename T> +bool operator!=(const QuicArenaScopedPtr<T>& left, std::nullptr_t) { + return left.get() != nullptr; +} + +template <typename T> +QuicArenaScopedPtr<T>::QuicArenaScopedPtr() : value_(nullptr) {} + +template <typename T> +QuicArenaScopedPtr<T>::QuicArenaScopedPtr(T* value) + : QuicArenaScopedPtr(value, ConstructFrom::kHeap) {} + +template <typename T> +template <typename U> +QuicArenaScopedPtr<T>::QuicArenaScopedPtr(QuicArenaScopedPtr<U>&& other) + : value_(other.value_) { + static_assert( + std::is_base_of<T, U>::value || std::is_same<T, U>::value, + "Cannot construct QuicArenaScopedPtr; type is not derived or same."); + other.value_ = nullptr; +} + +template <typename T> +template <typename U> +QuicArenaScopedPtr<T>& QuicArenaScopedPtr<T>::operator=( + QuicArenaScopedPtr<U>&& other) { + static_assert( + std::is_base_of<T, U>::value || std::is_same<T, U>::value, + "Cannot assign QuicArenaScopedPtr; type is not derived or same."); + swap(other); + return *this; +} + +template <typename T> +QuicArenaScopedPtr<T>::~QuicArenaScopedPtr() { + reset(); +} + +template <typename T> +T* QuicArenaScopedPtr<T>::get() const { + return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(value_) & + ~kFromArenaMask); +} + +template <typename T> +T& QuicArenaScopedPtr<T>::operator*() const { + return *get(); +} + +template <typename T> +T* QuicArenaScopedPtr<T>::operator->() const { + return get(); +} + +template <typename T> +void QuicArenaScopedPtr<T>::swap(QuicArenaScopedPtr& other) { + using std::swap; + swap(value_, other.value_); +} + +template <typename T> +bool QuicArenaScopedPtr<T>::is_from_arena() { + return (reinterpret_cast<uintptr_t>(value_) & kFromArenaMask) != 0; +} + +template <typename T> +void QuicArenaScopedPtr<T>::reset(T* value) { + if (value_ != nullptr) { + if (is_from_arena()) { + // Manually invoke the destructor. + get()->~T(); + } else { + delete get(); + } + } + DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(value) & kFromArenaMask); + value_ = value; +} + +template <typename T> +QuicArenaScopedPtr<T>::QuicArenaScopedPtr(void* value, ConstructFrom from_arena) + : value_(value) { + DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(value_) & kFromArenaMask); + switch (from_arena) { + case ConstructFrom::kHeap: + break; + case ConstructFrom::kArena: + value_ = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(value_) | + QuicArenaScopedPtr<T>::kFromArenaMask); + break; + } +} + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_QUIC_ARENA_SCOPED_PTR_H_