// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. // // 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. #ifndef FORTRAN_COMMON_UNWRAP_H_ #define FORTRAN_COMMON_UNWRAP_H_ #include "indirection.h" #include "reference-counted.h" #include #include #include #include // Given a nest of variants, optionals, &/or pointers, Unwrap<>() isolates // a packaged value of a specific type if it is present and returns a pointer // thereto; otherwise, it returns a null pointer. It's analogous to // std::get_if<>() but it accepts a reference argument and is recursive. // The target type parameter cannot be omitted. // // Be advised: If the target type parameter is not const-qualified, but the // isolated value is const-qualified, the result of Unwrap<> will be a // pointer to a const-qualified value. // // Further: const-qualified alternatives in instances of non-const-qualified // variants will not be returned from Unwrap if the target type is not // const-qualified. // // UnwrapCopy<>() is a variation of Unwrap<>() that returns an optional copy // of the value if one is present with the desired type. namespace Fortran::common { // Utility: Produces "const A" if B is const and A is not already so. template using Constify = std::conditional_t && !std::is_const_v, std::add_const_t, A>; // Base case template auto Unwrap(B &x) -> Constify * { if constexpr (std::is_same_v, std::decay_t>) { return &x; } else { return nullptr; } } // Prototypes of specializations, to enable mutual recursion template auto Unwrap(B *p) -> Constify *; template auto Unwrap(const std::unique_ptr &) -> Constify *; template auto Unwrap(const std::shared_ptr &) -> Constify *; template auto Unwrap(std::optional &) -> Constify *; template auto Unwrap(const std::optional &) -> std::add_const_t *; template A *Unwrap(std::variant &); template auto Unwrap(const std::variant &) -> std::add_const_t *; template auto Unwrap(const Indirection &) -> Constify *; template auto Unwrap(const OwningPointer &) -> Constify *; template auto Unwrap(const CountedReference &) -> Constify *; // Implementations of specializations template auto Unwrap(B *p) -> Constify * { if (p != nullptr) { return Unwrap(*p); } else { return nullptr; } } template auto Unwrap(const std::unique_ptr &p) -> Constify * { if (p.get() != nullptr) { return Unwrap(*p); } else { return nullptr; } } template auto Unwrap(const std::shared_ptr &p) -> Constify * { if (p.get() != nullptr) { return Unwrap(*p); } else { return nullptr; } } template auto Unwrap(std::optional &x) -> Constify * { if (x.has_value()) { return Unwrap(*x); } else { return nullptr; } } template auto Unwrap(const std::optional &x) -> Constify * { if (x.has_value()) { return Unwrap(*x); } else { return nullptr; } } template A *Unwrap(std::variant &u) { return std::visit( [](auto &x) -> A * { using Ty = std::decay_t(x))>; if constexpr (!std::is_const_v> || std::is_const_v) { return Unwrap(x); } return nullptr; }, u); } template auto Unwrap(const std::variant &u) -> std::add_const_t * { return std::visit( [](const auto &x) -> std::add_const_t * { return Unwrap(x); }, u); } template auto Unwrap(const Indirection &p) -> Constify * { return Unwrap(*p); } template auto Unwrap(const OwningPointer &p) -> Constify * { if (p.get() != nullptr) { return Unwrap(*p); } else { return nullptr; } } template auto Unwrap(const CountedReference &p) -> Constify * { if (p.get() != nullptr) { return Unwrap(*p); } else { return nullptr; } } // Returns a copy of a wrapped value, if present, otherwise a vacant optional. template std::optional UnwrapCopy(const B &x) { if (const A * p{Unwrap(x)}) { return std::make_optional(*p); } else { return std::nullopt; } } } #endif // FORTRAN_COMMON_UNWRAP_H_