/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include namespace unifex { namespace detail { // Queries about whether or not a given type, T, supports a given CPO. template inline constexpr bool supports_type_erased_cpo_v = false; template inline constexpr bool supports_type_erased_cpo_v = is_callable_r_v...>; template inline constexpr bool supports_type_erased_cpo_v = is_nothrow_callable_r_v...>; template inline constexpr bool supports_type_erased_cpos_v = (supports_type_erased_cpo_v< T, CPOs, typename CPOs::type_erased_signature_t> && ...); template < typename CPO, typename T, bool NoExcept, typename Ret, typename... Args> Ret _vtable_invoke( CPO cpo, replace_this_with_void_ptr_t... args) noexcept(NoExcept) { static_assert(!NoExcept || noexcept(extract_this{}(args...))); void* thisPointer = extract_this{}(args...); static_assert( !NoExcept || noexcept(Ret(((CPO &&) cpo)(replace_this::get( (decltype(args)&&)args, *static_cast(thisPointer))...)))); return ((CPO &&) cpo)(replace_this::get( (decltype(args)&&)args, *static_cast(thisPointer))...); } template struct inline_vtable_holder; template < typename CPO, typename Sig = typename CPO::type_erased_signature_t> struct vtable_entry; template struct vtable_entry { using fn_t = Ret(base_cpo_t, replace_this_with_void_ptr_t...) noexcept; constexpr fn_t* get() const noexcept { return fn_; } template static constexpr vtable_entry create() noexcept { return vtable_entry{ &_vtable_invoke, T, true, Ret, Args...>}; } private: template friend struct inline_vtable_holder; explicit constexpr vtable_entry(fn_t* fn) noexcept : fn_(fn) {} fn_t* fn_; }; template struct vtable_entry { using fn_t = Ret(base_cpo_t, replace_this_with_void_ptr_t...); constexpr fn_t* get() const noexcept { return fn_; } template static constexpr vtable_entry create() noexcept { return vtable_entry{ &_vtable_invoke, T, false, Ret, Args...>}; } private: template friend struct inline_vtable_holder; explicit constexpr vtable_entry(fn_t* fn) noexcept : fn_(fn) {} fn_t* fn_; }; template struct vtable : private vtable_entry... { template static constexpr vtable create() noexcept { return vtable{vtable_entry::template create()...}; } template constexpr auto get() const noexcept -> typename vtable_entry::fn_t* { const vtable_entry& entry = *this; return entry.get(); } private: friend inline_vtable_holder; explicit constexpr vtable(vtable_entry... entries) noexcept : vtable_entry{entries}... {} }; template struct indirect_vtable_holder { template static indirect_vtable_holder create() { static constexpr vtable v = vtable::template create(); return indirect_vtable_holder{v}; } const vtable& operator*() const noexcept { return *vtable_; } const vtable* operator->() const noexcept { return vtable_; } private: constexpr indirect_vtable_holder(const vtable& vtable) : vtable_(&vtable) {} const vtable* vtable_; }; template struct inline_vtable_holder { constexpr inline_vtable_holder( const inline_vtable_holder& other) noexcept = default; // Casting from an inline_vtable with a superset of vtable entries template /* implicit */ inline_vtable_holder( const inline_vtable_holder& other) noexcept : vtable_(vtable_entry(other->template get())...) {} // Casting from an indirect_vtable with a superset of vtable entries template /* implicit */ inline_vtable_holder( indirect_vtable_holder other) noexcept : vtable_(vtable_entry(other->template get())...) {} template static constexpr inline_vtable_holder create() { return inline_vtable_holder{vtable::template create()}; } const vtable& operator*() const noexcept { return vtable_; } const vtable* operator->() const noexcept { return &vtable_; } private: constexpr inline_vtable_holder(const vtable& vtable) : vtable_(vtable) {} vtable vtable_; }; } // namespace detail } // namespace unifex #include