/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include namespace folly { namespace channels { namespace detail { /** * A PointerVariant stores a pointer of one of two possible types. */ template class PointerVariant { public: template explicit PointerVariant(T* pointer) { set(pointer); } PointerVariant(PointerVariant&& other) noexcept : storage_(std::exchange(other.storage_, 0)) {} PointerVariant& operator=(PointerVariant&& other) noexcept { storage_ = std::exchange(other.storage_, 0); return *this; } /** * Returns the zero-based index of the type that is currently held. */ size_t index() const { return static_cast(storage_ & kTypeMask); } /** * Returns the pointer stored in the PointerVariant, if the type matches the * first type. If the stored type does not match the first type, an exception * will be thrown. */ inline FirstType* get(folly::tag_t) const { ensureCorrectType(false /* secondType */); return reinterpret_cast(storage_ & kPointerMask); } /** * Returns the pointer stored in the PointerVariant, if the type matches the * second type. If the stored type does not match the second type, an * exception will be thrown. */ inline SecondType* get(folly::tag_t) const { ensureCorrectType(true /* secondType */); return reinterpret_cast(storage_ & kPointerMask); } /** * Store a new pointer of type FirstType in the PointerVariant. */ void set(FirstType* pointer) { storage_ = reinterpret_cast(pointer); } /** * Store a new pointer of type SecondType in the PointerVariant. */ void set(SecondType* pointer) { storage_ = reinterpret_cast(pointer) | kTypeMask; } private: void ensureCorrectType(bool secondType) const { if (secondType != !!(storage_ & kTypeMask)) { throw std::runtime_error(fmt::format( "Incorrect type specified. Given: {}, Stored: {}", secondType ? folly::demangle(typeid(SecondType).name()) : folly::demangle(typeid(FirstType).name()), storage_ & kTypeMask ? folly::demangle(typeid(SecondType).name()) : folly::demangle(typeid(FirstType).name()))); } } static constexpr intptr_t kTypeMask = 1; static constexpr intptr_t kPointerMask = ~kTypeMask; intptr_t storage_; }; } // namespace detail } // namespace channels } // namespace folly