Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/bvt-appleclang-arm64e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
on:
workflow_call:
workflow_dispatch:

jobs:
bvt-appleclang-arm64e:
runs-on: macos-26
steps:
- uses: actions/checkout@v7

- name: Check toolchain versions
run: |
cc --version
xcodebuild -version
cmake --version
ninja --version

- name: Build and run test with AppleClang (arm64e with PAC) on cmake
run: |
cmake --preset default -DCMAKE_CXX_STANDARD=23 -DPROXY_BUILD_MODULES=FALSE -DCMAKE_OSX_ARCHITECTURES=arm64e
cmake --build --preset default -j
ctest --preset default -j
mkdir build/cmake/drop
bash ./tools/dump_build_env.sh c++ build/cmake/drop/env-info.json

- name: Build and run freestanding test with AppleClang (arm64e with PAC) on cmake
run: |
cmake --preset freestanding -DCMAKE_CXX_STANDARD=23 -DPROXY_BUILD_MODULES=FALSE -DCMAKE_OSX_ARCHITECTURES=arm64e
cmake --build --preset freestanding -j
ctest --preset freestanding -j

- name: Run benchmarks
run: build/cmake/benchmarks/msft_proxy_benchmarks --benchmark_min_warmup_time=0.1 --benchmark_min_time=0.1s --benchmark_repetitions=30 --benchmark_enable_random_interleaving=true --benchmark_report_aggregates_only=true --benchmark_format=json > build/cmake/drop/benchmarking-results.json

- name: Archive benchmarking results
uses: actions/upload-artifact@v7
with:
name: drop-apple-pac
path: build/cmake/drop/
6 changes: 5 additions & 1 deletion .github/workflows/pipeline-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ jobs:
name: Run BVT with AppleClang
if: github.event_name != 'push' || github.repository == 'ngcpp/proxy'

run-bvt-appleclang-arm64e:
uses: ./.github/workflows/bvt-appleclang-arm64e.yml
name: Run BVT with AppleClang (arm64e with PAC)

run-bvt-nvhpc:
uses: ./.github/workflows/bvt-nvhpc.yml
name: Run BVT with NVHPC
Expand All @@ -56,4 +60,4 @@ jobs:
report:
uses: ./.github/workflows/bvt-report.yml
name: Generate report
needs: [run-bvt-gcc, run-bvt-clang, run-bvt-msvc, run-bvt-appleclang, run-bvt-nvhpc, run-bvt-oneapi]
needs: [run-bvt-gcc, run-bvt-clang, run-bvt-msvc, run-bvt-appleclang, run-bvt-appleclang-arm64e, run-bvt-nvhpc, run-bvt-oneapi]
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Ignore build directories
build/
/build*
Testing/

# Python bytecode cache
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ if(BUILD_TESTING)
-Wall
-Wextra
-Wpedantic
$<$<CXX_COMPILER_ID:Clang>:-Wno-c++2b-extensions>
$<$<CXX_COMPILER_ID:Clang,AppleClang>:-Wno-c++2b-extensions>
)
set(PROXY_STRICT_WARNING_FLAGS ${PROXY_BUILD_FLAGS} -Werror)
endif()
Expand Down
6 changes: 2 additions & 4 deletions docs/spec/basic_facade_builder/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,8 @@ int main() {
static_assert(std::is_nothrow_move_constructible_v<pro::proxy<CopyableBase>>);
static_assert(std::is_nothrow_destructible_v<pro::proxy<CopyableBase>>);

static_assert(
std::is_trivially_copy_constructible_v<pro::proxy<TrivialBase>>);
static_assert(
std::is_trivially_move_constructible_v<pro::proxy<TrivialBase>>);
static_assert(std::is_nothrow_copy_constructible_v<pro::proxy<TrivialBase>>);
static_assert(std::is_nothrow_move_constructible_v<pro::proxy<TrivialBase>>);
static_assert(std::is_trivially_destructible_v<pro::proxy<TrivialBase>>);
}
```
Expand Down
8 changes: 8 additions & 0 deletions include/proxy/v4/detail/compatibility_check.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,12 @@ static_assert(sizeof(derived) == sizeof(char),
} // namespace pro::inline v4::detail::compatibility_check
#endif

#ifdef __has_feature
#if __has_feature(ptrauth_calls) && \
(!defined(__PTRAUTH__) || !__has_include(<ptrauth.h>))
#error "The Pointer Authentication feature is incomplete"
#endif // __has_feature(ptrauth_calls) && (!defined(__PTRAUTH__) ||
// !__has_include(<ptrauth.h>))
#endif // __has_feature

#endif // MSFT_PROXY_V4_DETAIL_COMPATIBILITY_CHECK_H_
134 changes: 41 additions & 93 deletions include/proxy/v4/detail/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <utility>

#include "../proxy_macros.h"
#include "./facade_meta_traits.h"

#if __has_cpp_attribute(msvc::no_unique_address)
#define PRO4D_NO_UNIQUE_ADDRESS_ATTRIBUTE msvc::no_unique_address
Expand All @@ -39,6 +40,9 @@ namespace detail {
template <class F>
struct basic_facade_traits;

template <class F>
struct meta_storage;

} // namespace detail

enum class constraint_level { none, nontrivial, nothrow, trivial };
Expand Down Expand Up @@ -232,14 +236,15 @@ struct proxy_helper {
proxy<F>& p_;
};

template <class M, class F>
static const M& get_meta(const proxy<F>& p) noexcept {
template <class F>
static const meta_storage<F>& get_meta(const proxy<F>& p) noexcept {
assert(p.has_value());
return static_cast<const M&>(*p.meta_.operator->());
return p.meta_;
}
template <class M, class F>
static const M& get_meta(const proxy_indirect_accessor<F>& p) noexcept {
return get_meta<M>(as_proxy<F, qualifier_type::const_lv>(p));
template <class F>
static const meta_storage<F>&
get_meta(const proxy_indirect_accessor<F>& p) noexcept {
return get_meta(as_proxy<F, qualifier_type::const_lv>(p));
}
template <class P, class F, qualifier_type Q>
static add_qualifier_t<P, Q> get_ptr(add_qualifier_t<proxy<F>, Q> p) {
Expand Down Expand Up @@ -348,32 +353,6 @@ consteval void diagnose_proxiable_required_convention_not_implemented() {
"not proxiable due to a required convention not implemented");
}

template <class ProP, class D, class O>
struct conv_meta;
#define PRO4D_DEF_CONV_META(oq, pq, ne, ...) \
template <class ProP, class D, class R, class... Args> \
struct conv_meta<ProP, D, R(Args...) oq ne> { \
conv_meta() = default; \
template <class P> \
constexpr explicit conv_meta(std::in_place_type_t<P>) \
: invoke([](ProP pq self, Args... args) ne -> R { \
return reinterpret_invoke<P, D, R>(static_cast<ProP pq>(self), \
std::forward<Args>(args)...); \
}) {} \
\
R (*invoke)(ProP pq, Args...) ne; \
}
PRO4D_DEF_OVERLOAD_SPECIALIZATIONS(PRO4D_DEF_CONV_META)
#undef PRO4D_DEF_CONV_META

template <class... Ms>
struct PRO4D_ENFORCE_EBO composite_meta : Ms... {
composite_meta() = default;
template <class P>
constexpr explicit composite_meta(std::in_place_type_t<P>)
: Ms(std::in_place_type<P>)... {}
};

template <class T>
consteval bool is_is_direct_well_formed() {
if constexpr (requires {
Expand Down Expand Up @@ -422,7 +401,7 @@ template <class C, class F, class... Os>
struct conv_traits_impl {
static_assert((overload_traits<substituted_overload_t<Os, F>>::applicable &&
...));
using meta = composite_meta<conv_meta<
using meta = std::tuple<invoker<
std::conditional_t<C::is_direct, proxy<F>, proxy_indirect_accessor<F>>,
typename C::dispatch_type, substituted_overload_t<Os, F>>...>;
template <class T>
Expand Down Expand Up @@ -513,10 +492,10 @@ template <class F, class D, class ONE, class OE, constraint_level C>
struct lifetime_meta_traits : std::type_identity<void> {};
template <class F, class D, class ONE, class OE>
struct lifetime_meta_traits<F, D, ONE, OE, constraint_level::nothrow>
: std::type_identity<conv_meta<proxy<F>, D, ONE>> {};
: std::type_identity<invoker<proxy<F>, D, ONE>> {};
template <class F, class D, class ONE, class OE>
struct lifetime_meta_traits<F, D, ONE, OE, constraint_level::nontrivial>
: std::type_identity<conv_meta<proxy<F>, D, OE>> {};
: std::type_identity<invoker<proxy<F>, D, OE>> {};
template <class F, class D, class ONE, class OE, constraint_level C>
using lifetime_meta_t = typename lifetime_meta_traits<F, D, ONE, OE, C>::type;

Expand Down Expand Up @@ -648,7 +627,7 @@ struct basic_facade_traits<F> : applicable_traits {};
template <class F, class... Cs>
struct facade_conv_traits_impl {
using conv_meta =
composite_t<composite_meta<>, typename conv_traits<Cs, F>::meta...>;
composite_t<std::tuple<>, typename conv_traits<Cs, F>::meta...>;
using conv_indirect_accessor =
composite_t<composite_accessor<>, conv_accessor_t<Cs, F, false>...>;
using conv_direct_accessor =
Expand All @@ -665,7 +644,7 @@ struct facade_conv_traits_impl {
};
template <class F, class... Rs>
struct facade_refl_traits_impl {
using refl_meta = composite_meta<
using refl_meta = std::tuple<
reflection_meta<Rs::is_direct, typename Rs::reflector_type>...>;
using refl_indirect_accessor =
composite_t<composite_accessor<>, refl_accessor_t<Rs, F, false>...>;
Expand All @@ -690,15 +669,18 @@ struct facade_traits : specialization_t<facade_conv_traits_impl,
typename F::convention_types, F>,
specialization_t<facade_refl_traits_impl,
typename F::reflection_types, F> {
using meta = composite_t<
composite_meta<>,
lifetime_meta_t<F, copy_dispatch, void(proxy<F>&) const noexcept,
void(proxy<F>&) const, F::copyability>,
lifetime_meta_t<F, relocate_dispatch, void(proxy<F>&) && noexcept,
void(proxy<F>&) &&, F::relocatability>,
lifetime_meta_t<F, destroy_dispatch, void() noexcept, void(),
F::destructibility>,
typename facade_traits::conv_meta, typename facade_traits::refl_meta>;
using meta_storage_base = specialization_t<
compact_facade_meta_traits::storage,
composite_t<
std::tuple<>,
lifetime_meta_t<F, copy_dispatch, void(proxy<F>&) const noexcept,
void(proxy<F>&) const, F::copyability>,
lifetime_meta_t<F, relocate_dispatch, void(proxy<F>&) && noexcept,
void(proxy<F>&) &&, F::relocatability>,
lifetime_meta_t<F, destroy_dispatch, void() noexcept, void(),
F::destructibility>,
typename facade_traits::conv_meta,
typename facade_traits::refl_meta>>;
using indirect_accessor =
composite_t<typename facade_traits::conv_indirect_accessor,
typename facade_traits::refl_indirect_accessor>;
Expand Down Expand Up @@ -728,47 +710,11 @@ struct facade_traits : specialization_t<facade_conv_traits_impl,
facade_traits::template refl_applicable_ptr<P>;
};

using ptr_prototype = void* [2];

template <class M>
struct meta_ptr_indirect_impl {
meta_ptr_indirect_impl() = default;
template <class P>
explicit meta_ptr_indirect_impl(std::in_place_type_t<P>)
: ptr_(&storage<P>) {}
bool has_value() const noexcept { return ptr_ != nullptr; }
void reset() noexcept { ptr_ = nullptr; }
const M* operator->() const noexcept { return ptr_; }

private:
const M* ptr_;
template <class P>
static inline const M storage{std::in_place_type<P>};
};
template <class M, class DM>
struct meta_ptr_direct_impl : private M {
using M::M;
bool has_value() const noexcept { return this->DM::invoke != nullptr; }
void reset() noexcept { this->DM::invoke = nullptr; }
const M* operator->() const noexcept { return this; }
template <class F>
struct meta_storage : facade_traits<F>::meta_storage_base {
using base = typename facade_traits<F>::meta_storage_base;
using base::base;
};
template <class M>
struct meta_ptr_traits_impl : std::type_identity<meta_ptr_indirect_impl<M>> {};
template <class ProP, class D, class O, class... Ms>
struct meta_ptr_traits_impl<composite_meta<conv_meta<ProP, D, O>, Ms...>>
: std::type_identity<
meta_ptr_direct_impl<composite_meta<conv_meta<ProP, D, O>, Ms...>,
conv_meta<ProP, D, O>>> {};
template <class M>
struct meta_ptr_traits : std::type_identity<meta_ptr_indirect_impl<M>> {};
template <class M>
requires(sizeof(M) <= sizeof(ptr_prototype) &&
alignof(M) <= alignof(ptr_prototype) &&
std::is_nothrow_default_constructible_v<M> &&
std::is_trivially_copyable_v<M>)
struct meta_ptr_traits<M> : meta_ptr_traits_impl<M> {};
template <class M>
using meta_ptr = typename meta_ptr_traits<M>::type;

template <class T>
class inplace_ptr {
Expand Down Expand Up @@ -796,8 +742,9 @@ class inplace_ptr {

template <class D, class O, class P, class... Args>
ret_t<O> invoke_impl(P&& p, Args&&... args) {
return proxy_helper::get_meta<conv_meta<std::remove_cvref_t<P>, D, O>>(p)
.invoke(std::forward<P>(p), std::forward<Args>(args)...);
return proxy_helper::get_meta(p)
.template get<invoker<std::remove_cvref_t<P>, D, O>>()(
std::forward<P>(p), std::forward<Args>(args)...);
}
template <class F, qualifier_type Q>
add_qualifier_t<proxy<F>, Q>
Expand Down Expand Up @@ -921,7 +868,8 @@ class proxy_indirect_accessor
}
template <class R>
friend const R& reflect(const proxy_indirect_accessor& p) noexcept {
return detail::proxy_helper::get_meta<detail::reflection_meta<false, R>>(p)
return detail::proxy_helper::get_meta(p)
.template get<detail::reflection_meta<false, R>>()
.reflector;
}
};
Expand Down Expand Up @@ -1159,7 +1107,8 @@ class proxy : public detail::facade_traits<F>::direct_accessor,
}
template <class R>
friend const R& reflect(const proxy& p) noexcept {
return detail::proxy_helper::get_meta<detail::reflection_meta<true, R>>(p)
return detail::proxy_helper::get_meta(p)
.template get<detail::reflection_meta<true, R>>()
.reflector;
}

Expand Down Expand Up @@ -1210,8 +1159,7 @@ class proxy : public detail::facade_traits<F>::direct_accessor,
P& result = *std::construct_at(reinterpret_cast<P*>(ptr_),
std::forward<Args>(args)...);
if constexpr (proxiable<P, F>) {
meta_ = detail::meta_ptr<typename detail::facade_traits<F>::meta>{
std::in_place_type<P>};
meta_ = detail::meta_storage<F>{std::in_place_type<P>};
} else {
detail::facade_traits<F>::template diagnose_proxiable_noreturn<P>();
}
Expand All @@ -1238,7 +1186,7 @@ class proxy : public detail::facade_traits<F>::direct_accessor,
*std::move(cself);
})

detail::meta_ptr<typename detail::facade_traits<F>::meta> meta_;
detail::meta_storage<F> meta_;
alignas(F::max_align) std::byte ptr_[F::max_size];
};

Expand Down
2 changes: 2 additions & 0 deletions include/proxy/v4/detail/facade_creation.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ consteval std::size_t max_align_of(std::size_t value) {
return value < alignof(std::max_align_t) ? value : alignof(std::max_align_t);
}

using ptr_prototype = void* [2];

template <class T, class U>
using merge_tuple_t = specialization_t<add_tuple_t, U, T>;
template <class C1, class C2>
Expand Down
Loading