From e5c426c3158dc32ae30f1668c845529e9a380c23 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Mon, 18 Sep 2023 20:07:08 +0100 Subject: [PATCH] Make `IsWall` easier for the compiler to inline This appears to be a very hot function. Makes it fully inlineable (even in Debug mode). --- Source/engine/render/scrollrt.cpp | 2 +- Source/levels/gendung.cpp | 7 +------ Source/levels/gendung.h | 8 ++++++-- Source/utils/enum_traits.h | 28 +++++++++++++++------------- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/Source/engine/render/scrollrt.cpp b/Source/engine/render/scrollrt.cpp index 71b1221121b..33b9995c2c9 100644 --- a/Source/engine/render/scrollrt.cpp +++ b/Source/engine/render/scrollrt.cpp @@ -843,7 +843,7 @@ void DrawFloor(const Surface &out, Point tilePosition, Point targetBufferPositio } } -bool IsWall(Point position) +[[nodiscard]] DVL_ALWAYS_INLINE bool IsWall(Point position) { return TileHasAny(dPiece[position.x][position.y], TileProperties::Solid) || dSpecial[position.x][position.y] != 0; } diff --git a/Source/levels/gendung.cpp b/Source/levels/gendung.cpp index 77d1ea44d5e..d781a31d7d2 100644 --- a/Source/levels/gendung.cpp +++ b/Source/levels/gendung.cpp @@ -27,7 +27,7 @@ std::unique_ptr pSetPiece; OptionalOwnedClxSpriteList pSpecialCels; std::unique_ptr pMegaTiles; std::unique_ptr pDungeonCels; -std::array SOLData; +TileProperties SOLData[MAXTILES]; WorldTilePosition dminPosition; WorldTilePosition dmaxPosition; dungeon_type leveltype; @@ -417,11 +417,6 @@ void CreateDungeon(uint32_t rseed, lvl_entry entry) Make_SetPC(SetPiece); } -bool TileHasAny(int tileId, TileProperties property) -{ - return HasAnyOf(SOLData[tileId], property); -} - void LoadLevelSOLData() { switch (leveltype) { diff --git a/Source/levels/gendung.h b/Source/levels/gendung.h index 4efade152a1..4dd5d0dda70 100644 --- a/Source/levels/gendung.h +++ b/Source/levels/gendung.h @@ -167,7 +167,7 @@ extern std::unique_ptr pDungeonCels; /** * List tile properties */ -extern DVL_API_FOR_TEST std::array SOLData; +extern DVL_API_FOR_TEST TileProperties SOLData[MAXTILES]; /** Specifies the minimum X,Y-coordinates of the map. */ extern WorldTilePosition dminPosition; /** Specifies the maximum X,Y-coordinates of the map. */ @@ -334,7 +334,11 @@ struct Miniset { } }; -bool TileHasAny(int tileId, TileProperties property); +[[nodiscard]] DVL_ALWAYS_INLINE bool TileHasAny(int tileId, TileProperties property) +{ + return HasAnyOf(SOLData[tileId], property); +} + void LoadLevelSOLData(); void SetDungeonMicros(); void DRLG_InitTrans(); diff --git a/Source/utils/enum_traits.h b/Source/utils/enum_traits.h index 7ad2f3fb75e..67496a07e3c 100644 --- a/Source/utils/enum_traits.h +++ b/Source/utils/enum_traits.h @@ -8,6 +8,8 @@ #include #include +#include "utils/attributes.h" + namespace devilution { template @@ -27,17 +29,17 @@ class enum_values { { } - const T operator*() const + [[nodiscard]] DVL_ALWAYS_INLINE const T operator*() const { return static_cast(m_value); } - void operator++() + DVL_ALWAYS_INLINE void operator++() { m_value++; } - bool operator!=(Iterator rhs) const + [[nodiscard]] DVL_ALWAYS_INLINE bool operator!=(Iterator rhs) const { return m_value != rhs.m_value; } @@ -45,13 +47,13 @@ class enum_values { }; template -typename enum_values::Iterator begin(enum_values) +[[nodiscard]] DVL_ALWAYS_INLINE typename enum_values::Iterator begin(enum_values) { return typename enum_values::Iterator(static_cast::type>(T::FIRST)); } template -typename enum_values::Iterator end(enum_values) +[[nodiscard]] DVL_ALWAYS_INLINE typename enum_values::Iterator end(enum_values) { return typename enum_values::Iterator(static_cast::type>(T::LAST) + 1); } @@ -66,54 +68,54 @@ struct is_flags_enum : std::false_type { }; template ::value && is_flags_enum::value, bool> = true> -constexpr EnumType operator|(EnumType lhs, EnumType rhs) +[[nodiscard]] DVL_ALWAYS_INLINE constexpr EnumType operator|(EnumType lhs, EnumType rhs) { using T = std::underlying_type_t; return static_cast(static_cast(lhs) | static_cast(rhs)); } template ::value && is_flags_enum::value, bool> = true> -constexpr EnumType operator|=(EnumType &lhs, EnumType rhs) +DVL_ALWAYS_INLINE constexpr EnumType operator|=(EnumType &lhs, EnumType rhs) { lhs = lhs | rhs; return lhs; } template ::value && is_flags_enum::value, bool> = true> -constexpr EnumType operator&(EnumType lhs, EnumType rhs) +[[nodiscard]] DVL_ALWAYS_INLINE constexpr EnumType operator&(EnumType lhs, EnumType rhs) { using T = std::underlying_type_t; return static_cast(static_cast(lhs) & static_cast(rhs)); } template ::value && is_flags_enum::value, bool> = true> -constexpr EnumType operator&=(EnumType &lhs, EnumType rhs) +DVL_ALWAYS_INLINE constexpr EnumType operator&=(EnumType &lhs, EnumType rhs) { lhs = lhs & rhs; return lhs; } template ::value && is_flags_enum::value, bool> = true> -constexpr EnumType operator~(EnumType value) +[[nodiscard]] DVL_ALWAYS_INLINE constexpr EnumType operator~(EnumType value) { using T = std::underlying_type_t; return static_cast(~static_cast(value)); } template ::value && is_flags_enum::value, bool> = true> -constexpr bool HasAnyOf(EnumType lhs, EnumType test) +[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool HasAnyOf(EnumType lhs, EnumType test) { return (lhs & test) != static_cast(0); // Some flags enums may not use a None value outside this check so we don't require an EnumType::None definition here. } template ::value && is_flags_enum::value, bool> = true> -constexpr bool HasAllOf(EnumType lhs, EnumType test) +[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool HasAllOf(EnumType lhs, EnumType test) { return (lhs & test) == test; } template ::value && is_flags_enum::value, bool> = true> -constexpr bool HasNoneOf(EnumType lhs, EnumType test) +[[nodiscard]] DVL_ALWAYS_INLINE constexpr bool HasNoneOf(EnumType lhs, EnumType test) { return !HasAnyOf(lhs, test); }