Skip to content

Commit

Permalink
Improve compile-time constraints for constants (#72)
Browse files Browse the repository at this point in the history
* Improve constraints: Require Facade::constraints and ctor of reflectionbe compile-time constants

* Supress clang warning

* Simplify code

* Fix compile error

* Refactoring

* Revert unit tests

* Refactor

* Refactoring

* Rename to is_consteval

* Formatting
  • Loading branch information
mingxwa authored Mar 6, 2024
1 parent 90c9db6 commit f3cfa4b
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 18 deletions.
36 changes: 25 additions & 11 deletions proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ struct first_applicable<T, I, Is...> : first_applicable<T, Is...> {};
template <template <class> class T, class... Is>
using first_applicable_t = typename first_applicable<T, Is...>::type;

template <class Expr>
consteval bool is_consteval(Expr)
{ return requires { typename std::bool_constant<(Expr{}(), false)>; }; }

template <class T>
consteval bool has_copyability(constraint_level level) {
switch (level) {
Expand Down Expand Up @@ -276,6 +280,24 @@ template <class... Ms, class I> requires(!std::is_void_v<I>)
struct facade_meta_reduction<composite_meta<Ms...>, I>
: std::type_identity<composite_meta<Ms..., I>> {};

template <class F>
consteval bool is_facade_constraints_well_formed() {
if constexpr (is_consteval([] { return F::constraints; })) {
return std::has_single_bit(F::constraints.max_align) &&
F::constraints.max_size % F::constraints.max_align == 0u;
}
return false;
}
template <class F, class P>
consteval bool is_facade_reflection_type_well_formed() {
using R = typename F::reflection_type;
if constexpr (std::is_void_v<R>) {
return true;
} else if constexpr (std::is_constructible_v<R, std::in_place_type_t<P>>) {
return is_consteval([] { return R{std::in_place_type<P>}; });
}
return false;
}
template <class... Ds>
struct default_dispatch_traits { using default_dispatch = void; };
template <class D>
Expand Down Expand Up @@ -306,24 +328,16 @@ struct facade_traits_impl<F, std::tuple<Ds...>>
has_relocatability<P>(F::constraints.relocatability) &&
has_destructibility<P>(F::constraints.destructibility) &&
(dispatch_traits<Ds>::template applicable_ptr<P> && ...) &&
(std::is_void_v<typename F::reflection_type> ||
std::is_nothrow_constructible_v<
typename F::reflection_type, std::in_place_type_t<P>>);
is_facade_reflection_type_well_formed<F, P>();
};
template <class F> struct facade_traits : inapplicable_traits {};
template <class F>
requires(
requires {
typename F::dispatch_types;
F::constraints;
{ F::constraints } -> std::same_as<const proxiable_ptr_constraints&>;
typename F::reflection_type;
} &&
std::is_same_v<decltype(F::constraints),
const proxiable_ptr_constraints> &&
std::has_single_bit(F::constraints.max_align) &&
F::constraints.max_size % F::constraints.max_align == 0u &&
(std::is_void_v<typename F::reflection_type> ||
std::is_trivially_copyable_v<typename F::reflection_type>))
} && is_facade_constraints_well_formed<F>())
struct facade_traits<F> : facade_traits_impl<F, typename F::dispatch_types> {};

using ptr_prototype = void*[2];
Expand Down
4 changes: 2 additions & 2 deletions tests/proxy_creation_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ namespace poly {
struct SboObserver {
public:
template <class P>
constexpr explicit SboObserver(std::in_place_type_t<pro::details::sbo_ptr<P>>) noexcept
constexpr explicit SboObserver(std::in_place_type_t<pro::details::sbo_ptr<P>>)
: SboEnabled(true) {}
template <class P>
constexpr explicit SboObserver(std::in_place_type_t<P>) noexcept
constexpr explicit SboObserver(std::in_place_type_t<P>)
: SboEnabled(false) {}

bool SboEnabled;
Expand Down
4 changes: 2 additions & 2 deletions tests/proxy_reflection_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ concept ReflectionApplicable = requires(pro::proxy<F> p) {
class RttiReflection {
public:
template <class P>
constexpr explicit RttiReflection(std::in_place_type_t<P>) noexcept
constexpr explicit RttiReflection(std::in_place_type_t<P>)
: type_(typeid(P)) {}

const char* GetName() const noexcept { return type_.name(); }
Expand All @@ -28,7 +28,7 @@ class RttiReflection {
struct TraitsReflection {
public:
template <class P>
constexpr explicit TraitsReflection(std::in_place_type_t<P>) noexcept
constexpr explicit TraitsReflection(std::in_place_type_t<P>)
: is_default_constructible_(std::is_default_constructible_v<P>),
is_copy_constructible_(std::is_copy_constructible_v<P>),
is_nothrow_move_constructible_(std::is_nothrow_move_constructible_v<P>),
Expand Down
21 changes: 18 additions & 3 deletions tests/proxy_traits_tests.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include <stdexcept>
#include <type_traits>
#include "proxy.h"

Expand Down Expand Up @@ -150,7 +151,7 @@ static_assert(sizeof(pro::proxy<TrivialFacade>) == 2 * sizeof(void*)); // VTABL

struct ReflectionOfSmallPtr {
template <class P> requires(sizeof(P) <= sizeof(void*))
constexpr ReflectionOfSmallPtr(std::in_place_type_t<P>) noexcept {}
constexpr ReflectionOfSmallPtr(std::in_place_type_t<P>) {}
};
PRO_DEF_FACADE(RelocatableFacadeWithReflection, PRO_MAKE_DISPATCH_PACK(), pro::relocatable_ptr_constraints, ReflectionOfSmallPtr);
static_assert(!pro::proxiable<MockMovablePtr, RelocatableFacadeWithReflection>);
Expand All @@ -159,6 +160,13 @@ static_assert(pro::proxiable<MockCopyableSmallPtr, RelocatableFacadeWithReflecti
static_assert(pro::proxiable<MockTrivialPtr, RelocatableFacadeWithReflection>);
static_assert(pro::proxiable<MockFunctionPtr, RelocatableFacadeWithReflection>);

struct RuntimeReflection {
template <class P>
explicit RuntimeReflection(std::in_place_type_t<P>) { throw std::runtime_error{"Not supported"}; }
};
PRO_DEF_FACADE(FacadeWithRuntimeReflection, PRO_MAKE_DISPATCH_PACK(), pro::relocatable_ptr_constraints, RuntimeReflection);
static_assert(!pro::proxiable<MockTrivialPtr, FacadeWithRuntimeReflection>);

struct BadFacade_MissingDispatchTypes {
#ifdef __clang__
#pragma clang diagnostic push
Expand Down Expand Up @@ -225,6 +233,13 @@ struct BadFacade_BadConstraints_BadSize {
};
static_assert(!pro::facade<BadFacade_BadConstraints_BadSize>);

struct BadFacade_BadConstraints_NotConstant {
using dispatch_types = std::tuple<>;
static inline const auto constraints = pro::relocatable_ptr_constraints;
using reflection_type = void;
};
static_assert(!pro::facade<BadFacade_BadConstraints_NotConstant>);

struct BadFacade_MissingReflectionType {
using dispatch_types = std::tuple<>;
static constexpr auto constraints = pro::relocatable_ptr_constraints;
Expand All @@ -234,8 +249,8 @@ static_assert(!pro::facade<BadFacade_MissingReflectionType>);
struct BadFacade_BadReflectionType {
using dispatch_types = std::tuple<>;
static constexpr auto constraints = pro::relocatable_ptr_constraints;
using reflection_type = std::unique_ptr<int>;
using reflection_type = std::unique_ptr<int>; // Probably constexpr, unknown until the evaluation of proxiablility
};
static_assert(!pro::facade<BadFacade_BadReflectionType>);
static_assert(pro::facade<BadFacade_BadReflectionType>);

} // namespace

0 comments on commit f3cfa4b

Please sign in to comment.