From a4efe99ccf20189538dd5ffd7c6c1002d57d7edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 6 Feb 2024 13:39:55 +0100 Subject: [PATCH] Math: move literals to inline Literals::FooLiterals subnamespaces. To allow people to cherry-pick just a subset of them if other code defines literals that may conflict. I first did that the same way as STL (so both namespaces inline), only to subsequently discover the horror that all literals are implicitly available in the enclosing Math namespace, thus preventing no conflicts at all. So the Literals namespace isn't getting inline, only the inner ones. This is also in preparation for introduction of Literals::ConstexprColorLiterals that would provide a constexpr variant of the _srgbf literals at the expense of having a large LUT in a header file. --- doc/changelog-old.dox | 2 +- doc/namespaces.dox | 27 ++++++++++++++++- doc/snippets/MagnumMath.cpp | 7 +++++ doc/types.dox | 33 +++++++++++---------- src/Magnum/Math/Angle.h | 58 +++++++++++++++++++++++++++++++------ src/Magnum/Math/Color.h | 51 +++++++++++++++++++++++--------- src/Magnum/Math/Half.h | 24 ++++++++++++--- 7 files changed, 157 insertions(+), 45 deletions(-) diff --git a/doc/changelog-old.dox b/doc/changelog-old.dox index 051cb66a2..1282fe35d 100644 --- a/doc/changelog-old.dox +++ b/doc/changelog-old.dox @@ -684,7 +684,7 @@ a high-level overview. - New @ref Math::Frustum class and @ref Math::Geometry::Intersection::pointFrustum(), `Math::Geometry::Intersection::boxFrustum()` functions (see [mosra/magnum#185](https://github.com/mosra/magnum/pull/185) -- New @ref Math::Half class, @link Math::Literals::operator""_h @endlink +- New @ref Math::Half class, @link Math::Literals::HalfLiterals::operator""_h @endlink literal and @ref Math::packHalf() and @ref Math::unpackHalf() functions - New @ref Math::Color3::fromSrgb(), @ref Math::Color3::toSrgb(), @ref Math::Color4::fromSrgbAlpha(), @ref Math::Color4::toSrgbAlpha() diff --git a/doc/namespaces.dox b/doc/namespaces.dox index d2228eea2..6175557c9 100644 --- a/doc/namespaces.dox +++ b/doc/namespaces.dox @@ -124,7 +124,12 @@ more information. /** @namespace Magnum::Math::Literals @brief Math literals -Literals for easy construction of angle and color values. +Literals for easy construction of angle, color and other values. The namespace +is further split to prevent potential ambiguity and conflicts with literals +defined by other code, but the second namespace level is @cpp inline @ce so to +get for example the color literals you can do either of these two: + +@snippet MagnumMath.cpp Literals-using This library is built as part of Magnum by default. To use this library with CMake, find the `Magnum` package and link to the `Magnum::Magnum` target: @@ -146,6 +151,26 @@ See @ref building, @ref cmake and @ref types for more information. library in the Magnum Singles repository for easier integration into your projects. See @ref singles and @ref Math for more information. */ +/** @namespace Magnum::Math::Literals::AngleLiterals +@brief Math angle literals +@m_since_latest + +See the @ref Literals namespace and the @ref Deg and @ref Rad classes for more +information. +*/ +/** @namespace Magnum::Math::Literals::ColorLiterals +@brief Math color literals +@m_since_latest + +See the @ref Literals namespace and the @ref Color3 and @ref Color4 classes for +more information. +*/ +/** @namespace Magnum::Math::Literals::HalfLiterals +@brief Math half-float literals +@m_since_latest + +See the @ref Literals namespace and the @ref Half class for more information. +*/ /** @dir Magnum/Math/Algorithms * @brief Namespace @ref Magnum::Math::Algorithms diff --git a/doc/snippets/MagnumMath.cpp b/doc/snippets/MagnumMath.cpp index fe5d90934..b1502301e 100644 --- a/doc/snippets/MagnumMath.cpp +++ b/doc/snippets/MagnumMath.cpp @@ -639,6 +639,13 @@ static_cast(q1); static_cast(q2); } +{ +/* [Literals-using] */ +using namespace Math::Literals; +using namespace Math::Literals::ColorLiterals; +/* [Literals-using] */ +} + { /* [Deg-usage] */ using namespace Math::Literals; diff --git a/doc/types.dox b/doc/types.dox index b8acca8b6..9f0adb326 100644 --- a/doc/types.dox +++ b/doc/types.dox @@ -110,16 +110,16 @@ equivalently (e.g. @ref Math::Vector "Math::Vector" or @ref Color3 instead of @ref Vector3). For easier entering of (s)RGB colors in hexadecimal format there are -@link Math::Literals::operator""_srgb() _srgb @endlink / -@link Math::Literals::operator""_srgbf() _srgbf @endlink, -@link Math::Literals::operator""_srgba() _srgba @endlink / -@link Math::Literals::operator""_srgbaf() _srgbaf @endlink, -@link Math::Literals::operator""_rgb() _rgb @endlink / -@link Math::Literals::operator""_rgbf() _rgbf @endlink and -@link Math::Literals::operator""_rgba() _rgba @endlink / -@link Math::Literals::operator""_rgbaf() _rgbaf @endlink literals in -@ref Math::Literals namespace. See their documentation for more information -about the differences. +@link Math::Literals::ColorLiterals::operator""_srgb() _srgb @endlink / +@link Math::Literals::ColorLiterals::operator""_srgbf() _srgbf @endlink, +@link Math::Literals::ColorLiterals::operator""_srgba() _srgba @endlink / +@link Math::Literals::ColorLiterals::operator""_srgbaf() _srgbaf @endlink, +@link Math::Literals::ColorLiterals::operator""_rgb() _rgb @endlink / +@link Math::Literals::ColorLiterals::operator""_rgbf() _rgbf @endlink and +@link Math::Literals::ColorLiterals::operator""_rgba() _rgba @endlink / +@link Math::Literals::ColorLiterals::operator""_rgbaf() _rgbaf @endlink +literals in the @ref Math::Literals namespace. See their documentation for more +information about the differences. @snippet MagnumMath.cpp types-literals-colors @@ -146,8 +146,8 @@ operations as not all CPU architecture have native support for half-floats and thus the operations would be done faster in a regular single-precision @ref Float. The class provides explicit constructors and conversion operators from/to @ref Float and @ref UnsignedShort and you can also use the -@link Math::Literals::operator""_h() _h @endlink literal that is provided in -the @ref Math::Literals namespace: +@link Math::Literals::HalfLiterals::operator""_h() _h @endlink literal that is +provided in the @ref Math::Literals namespace: @snippet MagnumMath.cpp types-literals-half @@ -169,10 +169,11 @@ outweight that in most practical use cases. These classes are *not* implicitly constructible or convertible from/to @ref Float or @ref Double, you have to either construct/convert them explicitly -or use custom @link Math::Literals::operator""_degf() _degf @endlink / -@link Math::Literals::operator""_deg() _deg @endlink and @link Math::Literals::operator""_radf() _radf @endlink -/ @link Math::Literals::operator""_rad() _rad @endlink literals that are -provided in the @ref Math::Literals namespace: +or use custom @link Math::Literals::AngleLiterals::operator""_degf() _degf @endlink +/ @link Math::Literals::AngleLiterals::operator""_deg() _deg @endlink and +@link Math::Literals::AngleLiterals::operator""_radf() _radf @endlink / +@link Math::Literals::AngleLiterals::operator""_rad() _rad @endlink literals +that are provided in the @ref Math::Literals namespace: @snippet MagnumMath.cpp types-literals-angles diff --git a/src/Magnum/Math/Angle.h b/src/Magnum/Math/Angle.h index 861e1c2f0..416a91300 100644 --- a/src/Magnum/Math/Angle.h +++ b/src/Magnum/Math/Angle.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class @ref Magnum::Math::Deg, @ref Magnum::Math::Rad, literal @link Magnum::Math::Literals::operator""_degf() @endlink, @link Magnum::Math::Literals::operator""_radf() @endlink, @link Magnum::Math::Literals::operator""_deg() @endlink, @link Magnum::Math::Literals::operator""_rad() @endlink + * @brief Class @ref Magnum::Math::Deg, @ref Magnum::Math::Rad, literal @link Magnum::Math::Literals::AngleLiterals::operator""_degf() @endlink, @link Magnum::Math::Literals::AngleLiterals::operator""_radf() @endlink, @link Magnum::Math::Literals::AngleLiterals::operator""_deg() @endlink, @link Magnum::Math::Literals::AngleLiterals::operator""_rad() @endlink */ #ifndef CORRADE_SINGLES_NO_DEBUG @@ -95,7 +95,9 @@ These silent errors are easily avoided by requiring explicit conversions: @snippet MagnumMath.cpp Deg-usage-explicit-conversion -@see @ref Magnum::Deg, @ref Magnum::Degh, @ref Magnum::Degd +@see @link Literals::AngleLiterals::operator""_degf() @endlink, + @link Literals::AngleLiterals::operator""_deg() @endlink, @ref Magnum::Deg, + @ref Magnum::Degh, @ref Magnum::Degd */ template class Deg: public Unit { public: @@ -135,7 +137,23 @@ template class Deg: public Unit { constexpr /*implicit*/ Deg(Unit value); }; +/* Unlike STL, where there's e.g. std::literals::string_literals with both + being inline, here's just the second inline because making both would cause + the literals to be implicitly available to all code in Math. Which isn't + great if there are eventually going to be conflicts. In case of STL the + expected use case was that literals are available to anybody who does + `using namespace std;`, that doesn't apply here as most APIs are in + subnamespaces that *should not* be pulled in via `using` as a whole. */ namespace Literals { + /** @todoc The inline causes "error: non-const getClassDef() called on + aliased member. Please report as a bug." on Doxygen 1.8.18, plus the + fork I have doesn't even mark them as inline in the XML output yet. And + it also duplicates the literal reference to parent namespace, adding + extra noise. Revisit once upgrading to a newer version. */ + #ifndef DOXYGEN_GENERATING_OUTPUT + inline + #endif + namespace AngleLiterals { /** @relatesalso Magnum::Math::Deg @brief Double-precision degree value literal @@ -161,13 +179,15 @@ Example usage: */ constexpr Deg operator "" _degf(long double value) { return Deg(Float(value)); } -} +}} /** @brief Angle in radians See @ref Deg for more information. -@see @ref Magnum::Rad, @ref Magnum::Radh, @ref Magnum::Radd +@see @link Literals::AngleLiterals::operator""_radf() @endlink, + @link Literals::AngleLiterals::operator""_rad() @endlink, @ref Magnum::Rad, + @ref Magnum::Radh, @ref Magnum::Radd */ template class Rad: public Unit { public: @@ -204,7 +224,23 @@ template class Rad: public Unit { constexpr /*implicit*/ Rad(Unit value); }; +/* Unlike STL, where there's e.g. std::literals::string_literals with both + being inline, here's just the second inline because making both would cause + the literals to be implicitly available to all code in Math. Which isn't + great if there are eventually going to be conflicts. In case of STL the + expected use case was that literals are available to anybody who does + `using namespace std;`, that doesn't apply here as most APIs are in + subnamespaces that *should not* be pulled in via `using` as a whole. */ namespace Literals { + /** @todoc The inline causes "error: non-const getClassDef() called on + aliased member. Please report as a bug." on Doxygen 1.8.18, plus the + fork I have doesn't even mark them as inline in the XML output yet. And + it also duplicates the literal reference to parent namespace, adding + extra noise. Revisit once upgrading to a newer version. */ + #ifndef DOXYGEN_GENERATING_OUTPUT + inline + #endif + namespace AngleLiterals { /** @relatesalso Magnum::Math::Rad @brief Double-precision radian value literal @@ -224,7 +260,7 @@ See @link operator""_degf() @endlink for more information. */ constexpr Rad operator "" _radf(long double value) { return Rad(Float(value)); } -} +}} template constexpr Deg::Deg(Unit value): Unit(T(180)*T(value)/Math::Constants::pi()) {} template constexpr Rad::Rad(Unit value): Unit(T(value)*Math::Constants::pi()/T(180)) {} @@ -261,7 +297,8 @@ namespace Corrade { namespace Utility { /** @tweakableliteral{Magnum::Math::Deg} -Parses the @link Magnum::Math::Literals::operator""_degf @endlink literal. +Parses the @link Magnum::Math::Literals::AngleLiterals::operator""_degf @endlink +literal. @experimental */ template<> struct MAGNUM_EXPORT TweakableParser> { @@ -279,7 +316,8 @@ template<> struct TweakableParser struct MAGNUM_EXPORT TweakableParser> { @@ -297,7 +335,8 @@ template<> struct TweakableParser struct MAGNUM_EXPORT TweakableParser> { @@ -315,7 +354,8 @@ template<> struct TweakableParser struct MAGNUM_EXPORT TweakableParser> { diff --git a/src/Magnum/Math/Color.h b/src/Magnum/Math/Color.h index 3ffcb5028..84804345e 100644 --- a/src/Magnum/Math/Color.h +++ b/src/Magnum/Math/Color.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class @ref Magnum::Math::Color3, @ref Magnum::Math::Color4, literal @link Magnum::Math::Literals::operator""_rgb() @endlink, @link Magnum::Math::Literals::operator""_rgba() @endlink, @link Magnum::Math::Literals::operator""_rgbf() @endlink, @link Magnum::Math::Literals::operator""_rgbaf() @endlink, @link Magnum::Math::Literals::operator""_srgb() @endlink, @link Magnum::Math::Literals::operator""_srgba() @endlink, @link Magnum::Math::Literals::operator""_srgbf() @endlink, @link Magnum::Math::Literals::operator""_srgbaf() @endlink + * @brief Class @ref Magnum::Math::Color3, @ref Magnum::Math::Color4, literal @link Magnum::Math::Literals::ColorLiterals::operator""_rgb() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_rgba() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_rgbf() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_rgbaf() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgb() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgba() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgbf() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgbaf() @endlink */ /* std::declval() is said to be in but libstdc++, libc++ and MSVC STL @@ -299,8 +299,10 @@ Conversion from and to HSV is done always using floating-point types, so hue is always in range in range @f$ [0.0\degree, 360.0\degree] @f$, saturation and value in range @f$ [0.0, 1.0] @f$. -@see @link operator""_rgb() @endlink, @link operator""_rgbf() @endlink, - @link operator""_srgb() @endlink, @link operator""_srgbf() @endlink, +@see @link Literals::ColorLiterals::operator""_rgb() @endlink, + @link Literals::ColorLiterals::operator""_rgbf() @endlink, + @link Literals::ColorLiterals::operator""_srgb() @endlink, + @link Literals::ColorLiterals::operator""_srgbf() @endlink, @ref Color4, @ref Magnum::Color3, @ref Magnum::Color3h, @ref Magnum::Color3ub, @ref Magnum::Color3us */ @@ -723,8 +725,10 @@ MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(3, Color3) @brief Color in linear RGBA color space See @ref Color3 for more information. -@see @link operator""_rgba() @endlink, @link operator""_rgbaf() @endlink, - @link operator""_srgba() @endlink, @link operator""_srgbaf() @endlink, +@see @link Literals::ColorLiterals::operator""_rgba() @endlink, + @link Literals::ColorLiterals::operator""_rgbaf() @endlink, + @link Literals::ColorLiterals::operator""_srgba() @endlink, + @link Literals::ColorLiterals::operator""_srgbaf() @endlink, @ref Magnum::Color4, @ref Magnum::Color4h, @ref Magnum::Color4ub, @ref Magnum::Color4us */ @@ -1297,7 +1301,23 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const ColorHsv&); #endif #endif +/* Unlike STL, where there's e.g. std::literals::string_literals with both + being inline, here's just the second inline because making both would cause + the literals to be implicitly available to all code in Math. Which isn't + great if there are eventually going to be conflicts. In case of STL the + expected use case was that literals are available to anybody who does + `using namespace std;`, that doesn't apply here as most APIs are in + subnamespaces that *should not* be pulled in via `using` as a whole. */ namespace Literals { + /** @todoc The inline causes "error: non-const getClassDef() called on + aliased member. Please report as a bug." on Doxygen 1.8.18, plus the + fork I have doesn't even mark them as inline in the XML output yet. And + it also duplicates the literal reference to parent namespace, adding + extra noise. Revisit once upgrading to a newer version. */ + #ifndef DOXYGEN_GENERATING_OUTPUT + inline + #endif + namespace ColorLiterals { /** @relatesalso Magnum::Math::Color3 @brief 8bit-per-channel linear RGB literal @@ -1465,7 +1485,7 @@ inline Color4 operator "" _srgbaf(unsigned long long value) { return Color4::fromSrgbAlphaInt(UnsignedInt(value)); } -} +}} #ifndef CORRADE_SINGLES_NO_DEBUG /** @@ -1553,8 +1573,9 @@ namespace Corrade { namespace Utility { /** @tweakableliteral{Magnum::Math::Color3} -Parses the @link Magnum::Math::Literals::operator""_rgb @endlink and -@link Magnum::Math::Literals::operator""_srgb @endlink literals. +Parses the @link Magnum::Math::Literals::ColorLiterals::operator""_rgb @endlink +and @link Magnum::Math::Literals::ColorLiterals::operator""_srgb @endlink +literals. @experimental */ template<> struct MAGNUM_EXPORT TweakableParser> { @@ -1571,8 +1592,8 @@ template<> struct MAGNUM_EXPORT TweakableParser struct MAGNUM_EXPORT TweakableParser> { @@ -1589,8 +1610,9 @@ template<> struct MAGNUM_EXPORT TweakableParser struct MAGNUM_EXPORT TweakableParser> { @@ -1603,8 +1625,9 @@ template<> struct MAGNUM_EXPORT TweakableParser struct MAGNUM_EXPORT TweakableParser> { diff --git a/src/Magnum/Math/Half.h b/src/Magnum/Math/Half.h index 6a4fc1de3..1ebd3ddb4 100644 --- a/src/Magnum/Math/Half.h +++ b/src/Magnum/Math/Half.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class @ref Magnum::Math::Half, literal @link Magnum::Math::Literals::operator""_h() @endlink + * @brief Class @ref Magnum::Math::Half, literal @link Magnum::Math::Literals::HalfLiterals::operator""_h() @endlink */ #ifndef CORRADE_SINGLES_NO_DEBUG @@ -59,7 +59,7 @@ thus the operations would be done faster in a regular single-precision The class provides explicit conversion from and to @ref Magnum::Float "Float", equality comparison with correct treatment of NaN values, promotion and -negation operator, an @link Literals::operator""_h() operator""_h() @endlink +negation operator, a @link Literals::HalfLiterals::operator""_h() @endlink literal and an @ref operator<<(Debug&, Half) debug operator. Internally the class uses @ref packHalf() and @ref unpackHalf(). Example usage: @@ -165,7 +165,23 @@ class Half { UnsignedShort _data; }; +/* Unlike STL, where there's e.g. std::literals::string_literals with both + being inline, here's just the second inline because making both would cause + the literals to be implicitly available to all code in Math. Which isn't + great if there are eventually going to be conflicts. In case of STL the + expected use case was that literals are available to anybody who does + `using namespace std;`, that doesn't apply here as most APIs are in + subnamespaces that *should not* be pulled in via `using` as a whole. */ namespace Literals { + /** @todoc The inline causes "error: non-const getClassDef() called on + aliased member. Please report as a bug." on Doxygen 1.8.18, plus the + fork I have doesn't even mark them as inline in the XML output yet. And + it also duplicates the literal reference to parent namespace, adding + extra noise. Revisit once upgrading to a newer version. */ + #ifndef DOXYGEN_GENERATING_OUTPUT + inline + #endif + namespace HalfLiterals { /** @relatesalso Magnum::Math::Half @brief Half-float literal @@ -174,7 +190,7 @@ See @ref Half for more information. */ inline Half operator "" _h(long double value) { return Half(Float(value)); } -} +}} #ifndef CORRADE_SINGLES_NO_DEBUG /** @@ -208,7 +224,7 @@ namespace Corrade { namespace Utility { /** @tweakableliteral{Magnum::Math::Half} -Parses the @link Magnum::Math::Literals::operator""_h @endlink literal. +Parses the @link Magnum::Math::Literals::HalfLiterals::operator""_h @endlink literal. */ template<> struct MAGNUM_EXPORT TweakableParser { TweakableParser() = delete;