Lots of windows fixes and some more improvements.

This commit is contained in:
2025-06-24 15:20:42 +02:00
parent 36a908ab8a
commit 573c431dbd
14 changed files with 379 additions and 63 deletions

View File

@@ -44,6 +44,11 @@ public:
{
MIJIN_ASSERT(base_ != nullptr, "Constructed non-nullable type with nullptr.");
}
// some compilers apparently need this since they are unable to do proper pattern matching ...
NotNullable(const NotNullable&) MIJIN_NOEXCEPT_IF(std::is_nothrow_copy_constructible_v<T>) = default;
NotNullable(NotNullable&&) MIJIN_NOEXCEPT_IF(std::is_nothrow_move_constructible_v<T>) = default;
template<typename TOther> requires(std::is_constructible_v<T, const TOther&>)
constexpr NotNullable(const NotNullable<TOther>& other) MIJIN_NOEXCEPT_IF((std::is_nothrow_constructible_v<T, const TOther&>))
: base_(other.base_)
@@ -70,6 +75,12 @@ public:
{
MIJIN_ASSERT(base_ != nullptr, "Constructed non-nullable type with nullptr.");
}
constexpr NotNullable(NotNullable&& other) MIJIN_NOEXCEPT_IF(std::is_nothrow_copy_constructible_v<T>)
requires(std::is_copy_constructible_v<T>)
: base_(other.base_)
{
MIJIN_ASSERT(base_ != nullptr, "Constructed non-nullable type with nullptr.");
}
constexpr NotNullable(NotNullable&& other) MIJIN_NOEXCEPT_IF(std::is_nothrow_move_constructible_v<T>)
requires(std::is_move_constructible_v<T>)
: base_(std::exchange(other.base_, nullptr))
@@ -78,8 +89,12 @@ public:
}
constexpr NotNullable(std::nullptr_t) MIJIN_DELETE("Type is not nullable.");
constexpr NotNullable& operator=(const NotNullable& other) MIJIN_NOEXCEPT_IF(std::is_nothrow_copy_constructible_v<T>)
requires(std::is_copy_constructible_v<T>)
// some compilers apparently need this since they are unable to do proper pattern matching ...
NotNullable& operator=(const NotNullable&) MIJIN_NOEXCEPT_IF(std::is_nothrow_copy_constructible_v<T>) = default;
NotNullable& operator=(NotNullable&&) MIJIN_NOEXCEPT_IF(std::is_nothrow_move_constructible_v<T>) = default;
constexpr NotNullable& operator=(const NotNullable& other) MIJIN_NOEXCEPT_IF(std::is_nothrow_copy_assignable_v<T>)
requires(std::is_copy_assignable_v<T>)
{
if (this != &other)
{
@@ -114,13 +129,13 @@ public:
return base_ != other.base_;
}
template<std::equality_comparable_with<T> TOther> requires(!std::is_same_v<TOther, std::nullptr_t>)
template<nullable_type TOther> requires(std::equality_comparable_with<T, TOther> && !std::is_same_v<TOther, std::nullptr_t>)
bool operator==(const TOther& other) MIJIN_NOEXCEPT_IF(noexcept(std::declval<T>() == std::declval<TOther>()))
{
return base_ == other;
}
template<std::equality_comparable_with<T> TOther> requires(!std::is_same_v<TOther, std::nullptr_t>)
template<nullable_type TOther> requires(std::equality_comparable_with<T, TOther> && !std::is_same_v<TOther, std::nullptr_t>)
bool operator!=(const TOther& other) MIJIN_NOEXCEPT_IF(noexcept(std::declval<T>() != std::declval<TOther>()))
{
return base_ != other;

View File

@@ -0,0 +1,42 @@
#pragma once
#if !defined(MIJIN_UTIL_MISC_HPP_INCLUDED)
#define MIJIN_UTIL_MISC_HPP_INCLUDED 1
#include <array>
#include <utility>
namespace mijin
{
//
// public functions
//
template<auto V, typename T>
constexpr decltype(auto) idValue(T&& value)
{
return std::forward<T>(value);
}
namespace impl
{
template<typename T, typename... TArgs>
struct ConstructArrayHelper
{
template<std::size_t... I>
static constexpr std::array<T, sizeof...(I)> construct(const TArgs&... args, std::index_sequence<I...>)
{
return {idValue<I>(T(args...))...};
}
};
}
template<typename T, std::size_t count, typename... TArgs>
constexpr std::array<T, count> constructArray(const TArgs&... args)
{
return impl::ConstructArrayHelper<T, TArgs...>::construct(args..., std::make_index_sequence<count>());
}
}
#endif // !defined(MIJIN_UTIL_MISC_HPP_INCLUDED)

View File

@@ -145,7 +145,7 @@ std::string getExecutablePath() MIJIN_NOEXCEPT
void* alignedAlloc(std::size_t alignment, std::size_t size) MIJIN_NOEXCEPT
{
#if MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
return _aligned_alloc(size, alignment);
return _aligned_malloc(size, alignment);
#else
return std::aligned_alloc(alignment, size);
#endif

View File

@@ -21,6 +21,9 @@ namespace mijin
// public types
//
struct Type_; // use as typevar
struct Any_; // use as placeholder in templates
template<typename T>
struct always_false
{
@@ -95,11 +98,88 @@ struct map_template {
using type_t = TTemplate<TPredicate<T>>;
};
template<typename T, typename... Types>
struct is_any_type : std::disjunction<std::is_same<T, Types>...> {};
template<template<typename...> typename TTemplate, typename TType>
struct is_template_instance : std::false_type {};
template<template<typename...> typename TTemplate, typename... TArgs>
struct is_template_instance<TTemplate, TTemplate<TArgs...>> : std::true_type {};
template<template<typename...> typename TTemplate, typename TType>
constexpr bool is_template_instance_v = is_template_instance<TTemplate, TType>::value;
namespace impl
{
template<template<typename...> typename TTemplate, typename... TArgsTTmpl>
struct tmpl_param_comparator
{
template<typename TTmpl, typename TInstance>
static constexpr bool compare_single = std::is_same_v<TTmpl, TInstance> or std::is_same_v<TTmpl, Any_>;
template<typename T>
struct matches : std::false_type {};
// original (which MSVC didn't like for some reason :/)
// template<typename... TArgsInstance>
// struct matches<TTemplate<TArgsInstance...>> : std::bool_constant<(compare_single<TArgsTTmpl, TArgsInstance> && ...)> {};
template<template<typename...> typename TOtherTemplate, typename... TArgsInstance> requires(is_template_instance_v<TTemplate, TOtherTemplate<TArgsInstance...>>)
struct matches<TOtherTemplate<TArgsInstance...>> : std::bool_constant<(compare_single<TArgsTTmpl, TArgsInstance> && ...)> {};
template<typename T>
using matches_t = matches<T>;
};
}
template<typename TTemplate, typename TType>
struct match_template_type : std::false_type {};
template<template<typename...> typename TTemplate, typename TType, typename... TArgs>
struct match_template_type<TTemplate<TArgs...>, TType> : impl::tmpl_param_comparator<TTemplate, TArgs...>::template matches_t<TType> {};
template<typename TTemplate, typename TType>
constexpr bool match_template_type_v = match_template_type<TTemplate, TType>::value;
// similar to std::is_same, but allows placeholders
// - is_type_or_impl<some_tmpl<Type_>, some_type> resolves to some_tmpl<some_type>
// - is_type_or_impl<some_tmpl<Any_, int>, some_type> checks if some_type is an instance of some_tmpl with int as 2nd parameter
template<typename TMatch, typename TConcrete>
struct type_matches
{
using type = std::is_same<TMatch, TConcrete>;
};
template<template<typename> typename TTmplMatch, typename TConcrete>
struct type_matches<TTmplMatch<Type_>, TConcrete>
{
using type = TTmplMatch<TConcrete>;
};
template<template<typename...> typename TTmplMatch, typename TConcrete, typename... TArgs>
struct type_matches<TTmplMatch<TArgs...>, TConcrete>
{
using type = match_template_type<TTmplMatch<TArgs...>, TConcrete>;
};
template<typename TMatch, typename TConcrete>
using type_matches_t = type_matches<TMatch, TConcrete>::type;
template<typename TMatch, typename TConcrete>
inline constexpr bool type_matches_v = type_matches_t<TMatch, TConcrete>::value;
template<typename TConcrete, typename... TMatches>
struct is_any_type : std::disjunction<std::is_same<TConcrete, TMatches>...> {};
template<typename TConcrete, typename... TMatches>
static constexpr bool is_any_type_v = is_any_type<TConcrete, TMatches...>::value;
template<typename TConcrete, typename... TMatches>
struct match_any_type : std::disjunction<type_matches_t<TMatches, TConcrete>...> {};
template<typename TConcrete, typename... TMatches>
static constexpr bool match_any_type_v = match_any_type<TConcrete, TMatches...>::value;
template<typename T, typename... Types>
static constexpr bool is_any_type_v = is_any_type<T, Types...>::value;
concept union_type = match_any_type_v<T, Types...>;
template<typename TElement, typename TCollection>
struct is_type_member;
@@ -139,15 +219,6 @@ struct TypeAtHelper<0, TArg, TArgs...>
template<std::size_t I, typename... TArgs>
using type_at_t = TypeAtHelper<I, TArgs...>::type_t;
template<template<typename...> typename TTemplate, typename TType>
struct is_template_instance : std::false_type {};
template<template<typename...> typename TTemplate, typename... TArgs>
struct is_template_instance<TTemplate, TTemplate<TArgs...>> : std::true_type {};
template<template<typename...> typename TTemplate, typename TType>
constexpr bool is_template_instance_v = is_template_instance<TTemplate, TType>::value;
template<typename TDefault, template<typename...> typename TOper, typename... TArgs>
struct detect_or
{
@@ -192,6 +263,34 @@ decltype(auto) delayEvaluation(TType&& value)
return static_cast<TType&&>(value);
}
#define MIJIN_STATIC_TESTS 1
#if MIJIN_STATIC_TESTS
namespace test
{
template<typename T, typename U>
struct MyTemplate {};
static_assert(match_template_type_v<MyTemplate<Any_, int>, MyTemplate<int, int>>);
static_assert(match_template_type_v<MyTemplate<Any_, Any_>, MyTemplate<int, int>>);
static_assert(type_matches_v<MyTemplate<Any_, int>, MyTemplate<int, int>>);
static_assert(type_matches_v<MyTemplate<Any_, Any_>, MyTemplate<int, int>>);
static_assert(!type_matches_v<MyTemplate<double, int>, MyTemplate<int, int>>);
static_assert(type_matches_v<MyTemplate<Any_, Any_>, MyTemplate<int, double>>);
static_assert(type_matches_v<std::is_pointer<Type_>, void*>);
static_assert(union_type<int, int>);
static_assert(!union_type<int>);
static_assert(!union_type<int, double>);
static_assert(union_type<MyTemplate<int, int>, MyTemplate<int, int>>);
static_assert(union_type<MyTemplate<int, int>, MyTemplate<Any_, int>>);
static_assert(union_type<MyTemplate<int, int>, MyTemplate<Any_, Any_>>);
static_assert(union_type<MyTemplate<int, int>, MyTemplate<double, double>, MyTemplate<Any_, Any_>>);
static_assert(!union_type<int*, int>);
static_assert(union_type<int*, std::is_pointer<Type_>>);
static_assert(!union_type<int, std::is_pointer<Type_>>);
}
#endif
} // namespace mijin
#endif // !defined(MIJIN_UTIL_TRAITS_HPP_INCLUDED)