/* * Copyright (c) 2021, Matthew Olsson * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include namespace PDF { class Object : public RefCounted { public: virtual ~Object() = default; [[nodiscard]] ALWAYS_INLINE u32 generation_index() const { return m_generation_index; } ALWAYS_INLINE void set_generation_index(u32 generation_index) { m_generation_index = generation_index; } #define DEFINE_ID(_, name) \ virtual bool is_##name() const { return false; } ENUMERATE_OBJECT_TYPES(DEFINE_ID) #undef DEFINE_ID virtual const char* type_name() const = 0; virtual String to_string(int indent) const = 0; private: u32 m_generation_index { 0 }; }; template [[nodiscard]] ALWAYS_INLINE static NonnullRefPtr object_cast(NonnullRefPtr obj #ifdef PDF_DEBUG , SourceLocation loc = SourceLocation::current() #endif ) { #ifdef PDF_DEBUG # define ENUMERATE_TYPES(class_name, snake_name) \ if constexpr (IsSame) { \ if (!obj->is_##snake_name()) { \ dbgln("{} invalid cast from type {} to type " #snake_name, loc, obj->type_name()); \ } \ } ENUMERATE_OBJECT_TYPES(ENUMERATE_TYPES) # undef ENUMERATE_TYPES #endif return static_ptr_cast(obj); } } namespace AK { template struct Formatter : Formatter { ErrorOr format(FormatBuilder& builder, T const& object) { return Formatter::format(builder, object.to_string(0)); } }; template struct Formatter> : Formatter { ErrorOr format(FormatBuilder& builder, NonnullRefPtr const& object) { return Formatter::format(builder, *object); } }; }