/* * Souffle - A Datalog Compiler * Copyright (c) 2021, The Souffle Developers. All rights reserved. * Licensed under the Universal Permissive License v 1.0 as shown at: * - https://opensource.org/licenses/UPL * - /licenses/SOUFFLE-UPL.txt */ /************************************************************************ * * @file DynamicCasting.h * * Common utilities for dynamic casting. * ***********************************************************************/ #pragma once #include "souffle/utility/Types.h" #include #include namespace souffle { /** * This class is used to tell as<> that cross-casting is allowed. * I use a named type rather than just a bool to make the code stand out. */ class AllowCrossCast {}; namespace detail { template constexpr bool is_valid_cross_cast_option = std::is_same_v || std::is_same_v; } /** * Helpers for `dynamic_cast`ing without having to specify redundant type qualifiers. * e.g. `as(p)` instead of `as(p)`. */ template >> auto as(A* x) { if constexpr (!std::is_same_v && !std::is_base_of_v, std::remove_const_t>) { static_assert(std::is_base_of_v, std::remove_const_t>, "`as` does not allow cross-type dyn casts. " "(i.e. `as` where `B <: A` is not true.) " "Such a cast is likely a mistake or typo."); } return dynamic_cast*>(x); } template || std::is_base_of_v>, typename = std::enable_if_t && !is_pointer_like>> auto as(A& x) { return as(&x); } template >> auto as(const A& x) { return as(x.get()); } template auto as(const std::reference_wrapper& x) { return as(x.get()); } /** * Down-casts and checks the cast has succeeded */ template auto& asAssert(A&& a) { auto* cast = as(std::forward(a)); assert(cast && "Invalid cast"); return *cast; } template Own UNSAFE_cast(Own x) { if constexpr (std::is_assignable_v, Own>) { return x; } else { if (!x) return {}; auto y = Own(as(x)); assert(y && "incorrect typed return"); x.release(); // release after assert so dbgr can report `x` if it fails return y; } } /** * Checks if the object of type Source can be casted to type Destination. */ template // [[deprecated("Use `as` and implicit boolean conversion instead.")]] bool isA(A&& src) { return as(std::forward(src)); } } // namespace souffle