From c853ffb5b2f75f5a889ed2e3ef89b818a736e87a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 13:50:49 +0200 Subject: Adding upstream version 1.3+ds. Signed-off-by: Daniel Baumann --- src/util/cast.h | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/util/cast.h (limited to 'src/util/cast.h') diff --git a/src/util/cast.h b/src/util/cast.h new file mode 100644 index 0000000..06fb088 --- /dev/null +++ b/src/util/cast.h @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * Hand-rolled LLVM-style RTTI system for class hierarchies where dynamic_cast isn't fast enough. + */ +#ifndef INKSCAPE_UTIL_CAST_H +#define INKSCAPE_UTIL_CAST_H + +#include + +/* + * In order to use this system with a class hierarchy, specialize the following templates for + * every member of the hierarchy. The only requirement is that + * + * first_tag <= first_tag <= last_tag + * + * exactly when S is a derived class of T. Then add to each class the line of boilerplate + * + * int tag() const override { return tag_of; } + */ +template inline constexpr int first_tag = std::enable_if::value; +template inline constexpr int last_tag = std::enable_if::value; + +/** + * Convenience function to retrieve the tag (class id) of a given type. + */ +template inline constexpr int tag_of = first_tag>>; + +/** + * Equivalent to the boolean value of dynamic_cast(...). + * + * If the supplied pointer is null, the check fails. + * + * To help catch redundant checks, checks that are known at compile time currently generate + * a compile error. Please feel free to remove these static_asserts if they become unhelpful. + */ +template +bool is(S const *s) +{ + if (!s) return false; + if constexpr (std::is_base_of_v) { + static_assert(!sizeof(T), "check is always true"); + return true; + } else if constexpr (std::is_base_of_v) { + auto const s_tag = s->tag(); + return first_tag <= s_tag && s_tag <= last_tag; + } else { + static_assert(!sizeof(T), "check is always false"); + return false; + } +} + +/** + * Equivalent to static_cast(...) where the const is deduced. + */ +template +auto cast_unsafe(S *s) +{ + return static_cast(s); +} + +template +auto cast_unsafe(S const *s) +{ + return static_cast(s); +} + +/** + * Equivalent to dynamic_cast(...) where the const is deduced. + * + * If the supplied pointer is null, the result is null. + * + * To help catch redundant casts, casts that are known at compile time currently generate + * a compile error. Please feel free to remove these static_asserts if they become unhelpful. + */ +template +auto cast(S *s) +{ + if constexpr (std::is_base_of_v) { + // Removed static assert; it complicates template "collect_items" + // static_assert(!sizeof(T), "cast is unnecessary"); + return cast_unsafe(s); + } else if constexpr (std::is_base_of_v) { + return is(s) ? cast_unsafe(s) : nullptr; + } else { + static_assert(!sizeof(T), "cast is impossible"); + return nullptr; + } +} + +#endif // INKSCAPE_UTIL_CAST_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : -- cgit v1.2.3