From c462eaf7114f16a977afe84d0a4590b33091a33f Mon Sep 17 00:00:00 2001 From: n0F4x <71129946+n0F4x@users.noreply.github.com> Date: Tue, 20 Aug 2024 09:36:24 +0200 Subject: [PATCH] Add: Better & fixed monadic optional operators (#70, #71) The return type of `and_then` and `transform` is now a `Optional`, since the return type is allowed to change and `OptionalWithFlagValue` might not support that type. Those two functions now also have correct const overloads. --- include/fastgltf/types.hpp | 84 ++++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 22 deletions(-) diff --git a/include/fastgltf/types.hpp b/include/fastgltf/types.hpp index c39d008ab..d257969ba 100644 --- a/include/fastgltf/types.hpp +++ b/include/fastgltf/types.hpp @@ -1020,6 +1020,19 @@ namespace fastgltf { static constexpr auto missing_value = static_cast(std::numeric_limits>::max()); }; + FASTGLTF_EXPORT template + class OptionalWithFlagValue; + + /** + * A type alias which checks if there is a specialization of OptionalFlagValue for T and "switches" + * between fastgltf::OptionalWithFlagValue and std::optional. + */ + FASTGLTF_EXPORT template + using Optional = std::conditional_t< + !std::is_same_v::missing_value)>>, + OptionalWithFlagValue, + std::optional>; + /** * A custom optional class for fastgltf, * which uses so-called "flag values" which are specific values of T that will never be present as an actual value. @@ -1030,7 +1043,7 @@ namespace fastgltf { * If no specialization for T of OptionalFlagValue is provided, a static assert will be triggered. * In those cases, use std::optional or fastgltf::Optional instead. */ - FASTGLTF_EXPORT template + template class OptionalWithFlagValue final { static_assert(!std::is_same_v::missing_value)>>, "OptionalWithFlagValue can only be used when there is an appropriate specialization of OptionalFlagValue."); @@ -1170,31 +1183,67 @@ namespace fastgltf { } template - [[nodiscard]] OptionalWithFlagValue and_then(F&& func)& { + [[nodiscard]] auto and_then(F&& func)& { + using U = std::remove_cv_t>>; + if (!has_value()) + return U(); + return std::invoke(std::forward(func), **this); + } + + template + [[nodiscard]] auto and_then(F&& func) const& { + using U = std::remove_cv_t>>; + if (!has_value()) + return U(); + return std::invoke(std::forward(func), **this); + } + + template + [[nodiscard]] auto and_then(F&& func)&& { + using U = std::remove_cv_t>>; + if (!has_value()) + return U(); + return std::invoke(std::forward(func), std::move(**this)); + } + + template + [[nodiscard]] auto and_then(F&& func) const&& { + using U = std::remove_cv_t>>; + if (!has_value()) + return U(); + return std::invoke(std::forward(func), std::move(**this)); + } + + template + [[nodiscard]] auto transform(F&& func)& { + using U = std::remove_cv_t>; if (!has_value()) - return std::nullopt; - return func(value()); + return Optional(); + return Optional(std::invoke(std::forward(func), **this)); } template - [[nodiscard]] OptionalWithFlagValue and_then(F&& func)&& { + [[nodiscard]] auto transform(F&& func) const& { + using U = std::remove_cv_t>; if (!has_value()) - return std::nullopt; - return func(std::move(value())); + return Optional(); + return Optional(std::invoke(std::forward(func), **this)); } template - [[nodiscard]] OptionalWithFlagValue transform(F&& func)& { + [[nodiscard]] auto transform(F&& func)&& { + using U = std::remove_cv_t>; if (!has_value()) - return std::nullopt; - return OptionalWithFlagValue(func(value())); + return Optional(); + return Optional(std::invoke(std::forward(func), std::move(**this))); } template - [[nodiscard]] OptionalWithFlagValue transform(F&& func)&& { + [[nodiscard]] auto transform(F&& func) const&& { + using U = std::remove_cv_t>; if (!has_value()) - return std::nullopt; - return OptionalWithFlagValue(func(std::move(value()))); + return Optional(); + return Optional(std::invoke(std::forward(func), std::move(**this))); } template @@ -1305,15 +1354,6 @@ namespace fastgltf { return opt.has_value() && *opt >= value; } - /** - * A type alias which checks if there is a specialization of OptionalFlagValue for T and "switches" - * between fastgltf::OptionalWithFlagValue and std::optional. - */ - FASTGLTF_EXPORT template - using Optional = std::conditional_t< - !std::is_same_v::missing_value)>>, - OptionalWithFlagValue, - std::optional>; #pragma endregion #pragma region Structs