Skip to content

Commit

Permalink
Almost implements #70
Browse files Browse the repository at this point in the history
- missing check that function provided for `and_then` returns an optional type
- improved function call with `std::invoke`

-also fixes test cases where `quat::value_ptr` wasn't renamed to `quat::data`
  • Loading branch information
n0F4x committed Aug 19, 2024
1 parent 884d231 commit 824ece9
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 15 deletions.
73 changes: 61 additions & 12 deletions include/fastgltf/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,19 @@ namespace fastgltf {
static constexpr auto missing_value = static_cast<BufferTarget>(std::numeric_limits<std::underlying_type_t<BufferTarget>>::max());
};

template<typename T>
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 <typename T>
using Optional = std::conditional_t<
!std::is_same_v<std::nullopt_t, std::remove_const_t<decltype(OptionalFlagValue<T>::missing_value)>>,
OptionalWithFlagValue<T>,
std::optional<T>>;

/**
* 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.
Expand Down Expand Up @@ -1170,31 +1183,67 @@ namespace fastgltf {
}

template <typename F>
[[nodiscard]] OptionalWithFlagValue<T> and_then(F&& func)& {
[[nodiscard]] auto and_then(F&& func)& {
using U = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<F, T&>>>;
if (!has_value())
return U();
return std::invoke(std::forward<F>(func), **this);
}

template <typename F>
[[nodiscard]] auto and_then(F&& func) const& {
using U = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<F, const T&>>>;
if (!has_value())
return U();
return std::invoke(std::forward<F>(func), **this);
}

template <typename F>
[[nodiscard]] auto and_then(F&& func)&& {
using U = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<F, T&&>>>;
if (!has_value())
return U();
return std::invoke(std::forward<F>(func), std::move(**this));
}

template <typename F>
[[nodiscard]] auto and_then(F&& func) const&& {
using U = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<F, const T&&>>>;
if (!has_value())
return U();
return std::invoke(std::forward<F>(func), std::move(**this));
}

template <typename F>
[[nodiscard]] auto transform(F&& func)& {
using U = std::remove_cv_t<std::invoke_result_t<F, T&>>;
if (!has_value())
return std::nullopt;
return func(value());
return Optional<U>();
return Optional<U>(std::invoke(std::forward<F>(func), **this));
}

template <typename F>
[[nodiscard]] OptionalWithFlagValue<T> and_then(F&& func)&& {
[[nodiscard]] auto transform(F&& func) const& {
using U = std::remove_cv_t<std::invoke_result_t<F, const T&>>;
if (!has_value())
return std::nullopt;
return func(std::move(value()));
return Optional<U>();
return Optional<U>(std::invoke(std::forward<F>(func), **this));
}

template <typename F>
[[nodiscard]] OptionalWithFlagValue<T> transform(F&& func)& {
[[nodiscard]] auto transform(F&& func)&& {
using U = std::remove_cv_t<std::invoke_result_t<F, T&&>>;
if (!has_value())
return std::nullopt;
return OptionalWithFlagValue<T>(func(value()));
return Optional<U>();
return Optional<U>(std::invoke(std::forward<F>(func), std::move(**this)));
}

template <typename F>
[[nodiscard]] OptionalWithFlagValue<T> transform(F&& func)&& {
[[nodiscard]] auto transform(F&& func) const&& {
using U = std::remove_cv_t<std::invoke_result_t<F, const T&&>>;
if (!has_value())
return std::nullopt;
return OptionalWithFlagValue<T>(func(std::move(value())));
return Optional<U>();
return Optional<U>(std::invoke(std::forward<F>(func), std::move(**this)));
}

template <typename F>
Expand Down
6 changes: 3 additions & 3 deletions tests/math_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ TEST_CASE("Test TRS parsing and optional decomposition", "[maths]") {
const auto* pDefaultTRS = std::get_if<fastgltf::TRS>(&assetWithMatrix->nodes.front().transform);
REQUIRE(pDefaultTRS != nullptr);
auto translation = glm::make_vec3(pDefaultTRS->translation.data());
auto rotation = glm::make_quat(pDefaultTRS->rotation.value_ptr());
auto rotation = glm::make_quat(pDefaultTRS->rotation.data());
auto scale = glm::make_vec3(pDefaultTRS->scale.data());
auto rotationMatrix = glm::toMat4(rotation);
auto transform = glm::translate(glm::mat4(1.0f), translation) * rotationMatrix * glm::scale(glm::mat4(1.0f), scale);
Expand All @@ -262,7 +262,7 @@ TEST_CASE("Test TRS parsing and optional decomposition", "[maths]") {
// Check if the decomposed components equal the original components.
const auto* pDecomposedTRS = std::get_if<fastgltf::TRS>(&assetDecomposed->nodes.back().transform);
REQUIRE(glm::make_vec3(pDecomposedTRS->translation.data()) == translation);
REQUIRE(glm::make_quat(pDecomposedTRS->rotation.value_ptr()) == rotation);
REQUIRE(glm::make_quat(pDecomposedTRS->rotation.data()) == rotation);
REQUIRE(glm::make_vec3(pDecomposedTRS->scale.data()) == scale);
}

Expand Down Expand Up @@ -290,7 +290,7 @@ TEST_CASE("Test TRS parsing and optional decomposition", "[maths]") {
// future, but I suspect using double in the decompose functions should help mitigate most
// of it.
REQUIRE(glm::make_vec3(translation.data()) == glmTranslation);
REQUIRE(glm::all(glm::epsilonEqual(glm::make_quat(rotation.value_ptr()), glmRotation, glm::epsilon<float>() * 10)));
REQUIRE(glm::all(glm::epsilonEqual(glm::make_quat(rotation.data()), glmRotation, glm::epsilon<float>() * 10)));
REQUIRE(glm::all(glm::epsilonEqual(glm::make_vec3(scale.data()), glmScale, glm::epsilon<float>())));
}
}

0 comments on commit 824ece9

Please sign in to comment.