diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index b4b62a2d0..fa37fc24f 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -17,13 +17,15 @@ set(LIB_UTIL_SRC util/logger.cpp util/android_logger.cpp util/file_logger.cpp - util/ostream_logger.cpp - util/syslog_logger.cpp - util/win32_logger.cpp util/logic.cpp util/mem.cpp + util/memfn_traits.cpp + util/memfn.cpp util/metrics_core.cpp util/metrics_types.cpp + util/ostream_logger.cpp + util/syslog_logger.cpp + util/win32_logger.cpp util/metrics.cpp util/object.cpp util/printer.cpp diff --git a/llarp/context.cpp b/llarp/context.cpp index b43932190..663c96479 100644 --- a/llarp/context.cpp +++ b/llarp/context.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -50,8 +51,7 @@ namespace llarp llarp::LogError("failed to load config file ", configfile); return false; } - using namespace std::placeholders; - config->visit(std::bind(&Context::iter_config, this, _1, _2, _3)); + config->visit(util::memFn(&Context::iter_config, this)); if(!disableMetrics) { diff --git a/llarp/exit/session.cpp b/llarp/exit/session.cpp index 1c21f9729..12a2534f5 100644 --- a/llarp/exit/session.cpp +++ b/llarp/exit/session.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace llarp { @@ -97,19 +98,11 @@ namespace llarp BaseSession::HandlePathBuilt(llarp::path::Path_ptr p) { path::Builder::HandlePathBuilt(p); - p->SetDropHandler(std::bind(&BaseSession::HandleTrafficDrop, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3)); - p->SetDeadChecker(std::bind(&BaseSession::CheckPathDead, this, - std::placeholders::_1, - std::placeholders::_2)); - p->SetExitTrafficHandler( - std::bind(&BaseSession::HandleTraffic, this, std::placeholders::_1, - std::placeholders::_2, std::placeholders::_3)); + p->SetDropHandler(util::memFn(&BaseSession::HandleTrafficDrop, this)); + p->SetDeadChecker(util::memFn(&BaseSession::CheckPathDead, this)); + p->SetExitTrafficHandler(util::memFn(&BaseSession::HandleTraffic, this)); + p->AddObtainExitHandler(util::memFn(&BaseSession::HandleGotExit, this)); - p->AddObtainExitHandler(std::bind(&BaseSession::HandleGotExit, this, - std::placeholders::_1, - std::placeholders::_2)); routing::ObtainExitMessage obtain; obtain.S = p->NextSeqNo(); obtain.T = llarp::randint(); diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index fc546e62a..2f22be377 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -150,9 +151,8 @@ namespace llarp } m_Exit = std::make_shared< llarp::exit::ExitSession >( exitRouter, - std::bind(&TunEndpoint::QueueInboundPacketForExit, this, - std::placeholders::_1), - router, m_NumPaths, numHops, ShouldBundleRC()); + util::memFn(&TunEndpoint::QueueInboundPacketForExit, this), router, + m_NumPaths, numHops, ShouldBundleRC()); llarp::LogInfo(Name(), " using exit at ", exitRouter); } if(k == "local-dns") diff --git a/llarp/iwp/iwp.cpp b/llarp/iwp/iwp.cpp index 025a665af..1c02b137c 100644 --- a/llarp/iwp/iwp.cpp +++ b/llarp/iwp/iwp.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace llarp { @@ -9,15 +10,14 @@ namespace llarp std::unique_ptr< ILinkLayer > NewServerFromRouter(AbstractRouter* r) { - using namespace std::placeholders; return NewServer( r->encryption(), std::bind(&AbstractRouter::rc, r), - std::bind(&AbstractRouter::HandleRecvLinkMessageBuffer, r, _1, _2), - std::bind(&AbstractRouter::OnSessionEstablished, r, _1), - std::bind(&AbstractRouter::CheckRenegotiateValid, r, _1, _2), - std::bind(&AbstractRouter::Sign, r, _1, _2), - std::bind(&AbstractRouter::OnConnectTimeout, r, _1), - std::bind(&AbstractRouter::SessionClosed, r, _1)); + util::memFn(&AbstractRouter::HandleRecvLinkMessageBuffer, r), + util::memFn(&AbstractRouter::OnSessionEstablished, r), + util::memFn(&AbstractRouter::CheckRenegotiateValid, r), + util::memFn(&AbstractRouter::Sign, r), + util::memFn(&AbstractRouter::OnConnectTimeout, r), + util::memFn(&AbstractRouter::SessionClosed, r)); } std::unique_ptr< ILinkLayer > diff --git a/llarp/messages/relay_commit.cpp b/llarp/messages/relay_commit.cpp index da4a60610..a33cbee3a 100644 --- a/llarp/messages/relay_commit.cpp +++ b/llarp/messages/relay_commit.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -161,9 +162,7 @@ namespace llarp bool LR_CommitRecord::BDecode(llarp_buffer_t* buf) { - using namespace std::placeholders; - return bencode_read_dict(std::bind(&LR_CommitRecord::OnKey, this, _1, _2), - buf); + return bencode_read_dict(util::memFn(&LR_CommitRecord::OnKey, this), buf); } bool diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 7795095da..fde272c86 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -462,8 +463,7 @@ namespace llarp bool Router::Configure(Config *conf) { - using namespace std::placeholders; - conf->visit(std::bind(&Router::router_iter_config, this, _1, _2, _3)); + conf->visit(util::memFn(&Router::router_iter_config, this)); if(!InitOutboundLinks()) return false; if(!Ready()) @@ -1147,9 +1147,10 @@ namespace llarp void Router::ServiceNodeLookupRouterWhenExpired(RouterID router) { - dht()->impl->LookupRouter(router, - std::bind(&Router::HandleDHTLookupForExplore, - this, router, std::placeholders::_1)); + using namespace std::placeholders; + dht()->impl->LookupRouter( + router, + std::bind(&Router::HandleDHTLookupForExplore, this, router, _1)); } void @@ -1926,9 +1927,7 @@ namespace llarp bool Validate() { - using namespace std::placeholders; - config->visit( - std::bind(&RouterConfigValidator::ValidateEntry, this, _1, _2, _3)); + config->visit(util::memFn(&RouterConfigValidator::ValidateEntry, this)); return valid; } }; diff --git a/llarp/rpc/rpc.cpp b/llarp/rpc/rpc.cpp index 1da08bd91..47d6b1a6b 100644 --- a/llarp/rpc/rpc.cpp +++ b/llarp/rpc/rpc.cpp @@ -7,6 +7,7 @@ #include #include +#include #include namespace llarp @@ -151,8 +152,7 @@ namespace llarp { LogInfo("Updating service node list"); QueueRPC("get_all_service_nodes_keys", nlohmann::json::object(), - std::bind(&CallerImpl::NewAsyncUpdatePubkeyListConn, this, - std::placeholders::_1)); + util::memFn(&CallerImpl::NewAsyncUpdatePubkeyListConn, this)); } bool @@ -166,8 +166,7 @@ namespace llarp { return new GetServiceNodeListHandler( impl, this, - std::bind(&CallerImpl::HandleServiceNodeListUpdated, this, - std::placeholders::_1, std::placeholders::_2)); + util::memFn(&CallerImpl::HandleServiceNodeListUpdated, this)); } void diff --git a/llarp/service/async_key_exchange.cpp b/llarp/service/async_key_exchange.cpp index 7a3140ec9..559064d27 100644 --- a/llarp/service/async_key_exchange.cpp +++ b/llarp/service/async_key_exchange.cpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace llarp { @@ -50,9 +51,7 @@ namespace llarp // compure post handshake session key // PKE (A, B, N) SharedSecret sharedSecret; - using namespace std::placeholders; - path_dh_func dh_client = - std::bind(&Crypto::dh_client, crypto, _1, _2, _3, _4); + path_dh_func dh_client = util::memFn(&Crypto::dh_client, crypto); if(!self->m_LocalIdentity.KeyExchange(dh_client, sharedSecret, self->remote, self->frame.N)) { diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index e6a5a961b..ee36641d1 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include namespace llarp @@ -795,11 +796,9 @@ namespace llarp void Endpoint::HandlePathBuilt(path::Path_ptr p) { - using namespace std::placeholders; - p->SetDataHandler( - std::bind(&Endpoint::HandleHiddenServiceFrame, this, _1, _2)); - p->SetDropHandler(std::bind(&Endpoint::HandleDataDrop, this, _1, _2, _3)); - p->SetDeadChecker(std::bind(&Endpoint::CheckPathIsDead, this, _1, _2)); + p->SetDataHandler(util::memFn(&Endpoint::HandleHiddenServiceFrame, this)); + p->SetDropHandler(util::memFn(&Endpoint::HandleDataDrop, this)); + p->SetDeadChecker(util::memFn(&Endpoint::CheckPathIsDead, this)); path::Builder::HandlePathBuilt(p); } @@ -982,8 +981,7 @@ namespace llarp using namespace std::placeholders; HiddenServiceAddressLookup* job = new HiddenServiceAddressLookup( - this, std::bind(&Endpoint::OnLookup, this, _1, _2, _3), remote, - GenTXID()); + this, util::memFn(&Endpoint::OnLookup, this), remote, GenTXID()); LogInfo("doing lookup for ", remote, " via ", path->Endpoint()); if(job->SendRequestViaPath(path, Router())) { diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index a154fc7f3..49d4e2659 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace llarp { @@ -127,12 +128,9 @@ namespace llarp /// don't use it if we are marked bad if(markedBad) return; - p->SetDataHandler(std::bind(&OutboundContext::HandleHiddenServiceFrame, - this, std::placeholders::_1, - std::placeholders::_2)); - p->SetDropHandler(std::bind(&OutboundContext::HandleDataDrop, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3)); + p->SetDataHandler( + util::memFn(&OutboundContext::HandleHiddenServiceFrame, this)); + p->SetDropHandler(util::memFn(&OutboundContext::HandleDataDrop, this)); // we now have a path to the next intro, swap intros if(p->Endpoint() == m_NextIntro.router && remoteIntro != m_NextIntro) SwapIntros(); @@ -198,10 +196,7 @@ namespace llarp if(path) { HiddenServiceAddressLookup* job = new HiddenServiceAddressLookup( - m_Endpoint, - std::bind(&OutboundContext::OnIntroSetUpdate, this, - std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3), + m_Endpoint, util::memFn(&OutboundContext::OnIntroSetUpdate, this), addr, m_Endpoint->GenTXID()); updatingIntroSet = job->SendRequestViaPath(path, m_Endpoint->Router()); diff --git a/llarp/service/protocol.cpp b/llarp/service/protocol.cpp index d4d9599b7..1912e127d 100644 --- a/llarp/service/protocol.cpp +++ b/llarp/service/protocol.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace llarp { @@ -315,9 +316,8 @@ namespace llarp // PKE (A, B, N) SharedSecret sharedSecret; - using namespace std::placeholders; - path_dh_func dh_server = std::bind( - &Crypto::dh_server, CryptoManager::instance(), _1, _2, _3, _4); + path_dh_func dh_server = + util::memFn(&Crypto::dh_server, CryptoManager::instance()); if(!self->m_LocalIdentity.KeyExchange(dh_server, sharedSecret, self->msg->sender, self->frame.N)) diff --git a/llarp/util/memfn.cpp b/llarp/util/memfn.cpp new file mode 100644 index 000000000..38d8de530 --- /dev/null +++ b/llarp/util/memfn.cpp @@ -0,0 +1 @@ +#include diff --git a/llarp/util/memfn.hpp b/llarp/util/memfn.hpp new file mode 100644 index 000000000..4245c5488 --- /dev/null +++ b/llarp/util/memfn.hpp @@ -0,0 +1,91 @@ +#ifndef LLARP_UTIL_MEMFN +#define LLARP_UTIL_MEMFN + +#include +#include +#include + +#include +#include + +namespace llarp +{ + namespace util + { + template < typename Obj > + struct MemFnDereference + { + // clang-format off + static inline Obj& derefImp(Obj& obj, std::false_type) + { + return obj; + } + + template < typename Type > + static inline Obj& derefImp(Type& obj, std::true_type) + { + return *obj; + } + + template < typename Type > + static inline Obj& derefImp(const Type& obj, std::true_type) + { + return *obj; + } + + template < typename Type > + static inline Obj& deref(Type& obj) + { + return derefImp(obj, traits::is_pointy< Type >()); + } + + template < typename Type > + static inline Obj& deref(const Type& obj) + { + return derefImp(obj, traits::is_pointy< Type >()); + } + // clang-format on + }; + + template < typename Prototype, typename Instance > + class MemFn + { + using traits = MemFnTraits< Prototype >; + + static_assert(traits::IsMemFn, ""); + + public: + using result_type = typename traits::result_type; + + private: + Prototype m_func; + object::Proxy< Instance > m_instance; + + using Deref = MemFnDereference< typename traits::class_type >; + + public: + MemFn(Prototype prototype, const Instance& instance) + : m_func(prototype), m_instance(instance) + { + } + + template < typename... Args > + result_type + operator()(Args&&... args) const + { + return (Deref::deref(m_instance.value()) + .*m_func)(std::forward< Args >(args)...); + } + }; + + template < typename Prototype, typename Instance > + MemFn< Prototype, Instance > + memFn(Prototype prototype, const Instance& instance) + { + return MemFn< Prototype, Instance >(prototype, instance); + } + + } // namespace util +} // namespace llarp + +#endif diff --git a/llarp/util/memfn_traits.cpp b/llarp/util/memfn_traits.cpp new file mode 100644 index 000000000..ff0bd49e6 --- /dev/null +++ b/llarp/util/memfn_traits.cpp @@ -0,0 +1 @@ +#include diff --git a/llarp/util/memfn_traits.hpp b/llarp/util/memfn_traits.hpp new file mode 100644 index 000000000..613d0bf63 --- /dev/null +++ b/llarp/util/memfn_traits.hpp @@ -0,0 +1,107 @@ +#ifndef LLARP_UTIL_MEMFN_TRAITS +#define LLARP_UTIL_MEMFN_TRAITS + +#include +#include + +#include +#include + +namespace llarp +{ + namespace util + { + template < typename Prototype, typename TestPrototype > + struct MemFnTraitsImpl; + + template < typename Prototype > + struct MemFnTraits : public MemFnTraitsImpl< Prototype, Prototype > + { + }; + + template < typename Prototype, typename Return, typename Type, + typename... Args > + class MemFnTraitsClass + { + using NonCVTag = traits::Tag< 0 >; + using ConstTag = traits::Tag< 1 >; + using VolTag = traits::Tag< 2 >; + using ConstVolTag = traits::Tag< 3 >; + + // clang-format off + static constexpr NonCVTag test(Return (Type::*)(Args...)); + static constexpr ConstTag test(Return (Type::*)(Args...) const); + static constexpr VolTag test(Return (Type::*)(Args...) volatile); + static constexpr ConstVolTag test(Return (Type::*)(Args...) const volatile); + // clang-format on + public: + static constexpr bool IsConst = + ((sizeof((test)((Prototype)0)) - 1) & 1) != 0; + static constexpr bool IsVolatile = + ((sizeof((test)((Prototype)0)) - 1) & 2) != 0; + + using ctype = std::conditional_t< IsConst, const Type, Type >; + using type = std::conditional_t< IsVolatile, volatile ctype, ctype >; + }; + + template < typename Prototype, typename Return, typename Type, + typename... Args > + struct MemFnTraitsImpl< Prototype, Return (Type::*)(Args...) > + { + static constexpr bool IsMemFn = true; + + using class_type = + typename MemFnTraitsClass< Prototype, Return, Type, Args... >::type; + + using result_type = Return; + }; + + template < typename Prototype, typename Return, typename Type, + typename... Args > + struct MemFnTraitsImpl< Prototype, Return (Type::*)(Args...) const > + { + static constexpr bool IsMemFn = true; + + using class_type = + typename MemFnTraitsClass< Prototype, Return, Type, Args... >::type; + + using result_type = Return; + }; + + template < typename Prototype, typename Return, typename Type, + typename... Args > + struct MemFnTraitsImpl< Prototype, Return (Type::*)(Args...) volatile > + { + static constexpr bool IsMemFn = true; + + using class_type = + typename MemFnTraitsClass< Prototype, Return, Type, Args... >::type; + + using result_type = Return; + }; + + template < typename Prototype, typename Return, typename Type, + typename... Args > + struct MemFnTraitsImpl< Prototype, + Return (Type::*)(Args...) const volatile > + { + static constexpr bool IsMemFn = true; + + using class_type = + typename MemFnTraitsClass< Prototype, Return, Type, Args... >::type; + + using result_type = Return; + }; + + template < typename Prototype, typename TestPrototype > + struct MemFnTraitsImpl + { + static constexpr bool IsMemFn = false; + + using result_type = void; + using class_type = void; + }; + } // namespace util +} // namespace llarp + +#endif diff --git a/llarp/util/object.hpp b/llarp/util/object.hpp index bd4d922ca..71b3d8871 100644 --- a/llarp/util/object.hpp +++ b/llarp/util/object.hpp @@ -56,6 +56,54 @@ namespace llarp } }; + template < typename Value > + class Proxy + { + Buffer< Value > m_value; + + Proxy& + operator=(const Proxy&) = delete; + + public: + Proxy() + { + ::new(m_value.buffer()) Value(); + } + + Proxy(const Proxy& other) + { + ::new(m_value.buffer()) Value(other.value()); + } + + Proxy(const Value& value) + { + ::new(m_value.buffer()) Value(value); + } + + // template < typename... Args > + // Proxy(Args&&... args) + // { + // ::new(m_value.buffer()) Value(std::forward< Args >(args)...); + // } + + ~Proxy() + { + m_value.address()->~Value(); + } + + Value& + value() + { + return m_value.value(); + } + + const Value& + value() const + { + return m_value.value(); + } + }; + template < typename Value > class Catalog; template < typename Value > diff --git a/llarp/util/traits.hpp b/llarp/util/traits.hpp index ef21cdf27..2e39311e0 100644 --- a/llarp/util/traits.hpp +++ b/llarp/util/traits.hpp @@ -1,6 +1,8 @@ #ifndef LLARP_TRAITS_HPP #define LLARP_TRAITS_HPP +#include + #include #include #include @@ -10,14 +12,39 @@ namespace llarp { namespace traits { + using absl::conjunction; + using absl::disjunction; + using absl::void_t; + /// Represents the empty type struct Bottom { }; - /// C++17 compatibility. template pack - template < class... > - using void_t = void; + /// Int tag + template < size_t N > + struct Tag + { + char arr[N + 1]; + }; + + /// Type trait representing whether a type is pointer-like + template < typename T, typename _ = void > + struct is_pointy : public std::false_type + { + }; + + // We take the following things: + // - has element_type typedef + // - has dereference operator + // - has arrow operator + template < typename T > + struct is_pointy< + T, + std::conditional_t< false, void_t< decltype(*std::declval< T >()) >, + void > > : public std::true_type + { + }; /// Type trait representing whether a type is an STL-style container template < typename T, typename _ = void > diff --git a/llarp/utp/session.cpp b/llarp/utp/session.cpp index 5ef039b6f..0dcda28a9 100644 --- a/llarp/utp/session.cpp +++ b/llarp/utp/session.cpp @@ -4,13 +4,12 @@ #include #include #include +#include namespace llarp { namespace utp { - using namespace std::placeholders; - void Session::OnLinkEstablished(ILinkLayer* p) { @@ -613,7 +612,7 @@ namespace llarp ABSL_ATTRIBUTE_UNUSED void* res = utp_set_userdata(sock, this); assert(res == this); assert(s == sock); - GotLIM = std::bind(&InboundSession::InboundLIM, this, _1); + GotLIM = util::memFn(&InboundSession::InboundLIM, this); } bool @@ -678,7 +677,7 @@ namespace llarp gotLIM = true; EnterState(eSessionReady); /// future LIM are used for session renegotiation - GotLIM = std::bind(&Session::GotSessionRenegotiate, this, _1); + GotLIM = util::memFn(&Session::GotSessionRenegotiate, this); } return true; } @@ -702,7 +701,7 @@ namespace llarp assert(res == this); assert(s == sock); - GotLIM = std::bind(&OutboundSession::OutboundLIM, this, _1); + GotLIM = util::memFn(&OutboundSession::OutboundLIM, this); } void @@ -729,7 +728,7 @@ namespace llarp return false; } /// future LIM are used for session renegotiation - GotLIM = std::bind(&Session::GotSessionRenegotiate, this, _1); + GotLIM = util::memFn(&Session::GotSessionRenegotiate, this); EnterState(eSessionReady); return true; } diff --git a/llarp/utp/utp.cpp b/llarp/utp/utp.cpp index da544d9cd..495199bcd 100644 --- a/llarp/utp/utp.cpp +++ b/llarp/utp/utp.cpp @@ -1,14 +1,13 @@ #include -#include #include +#include +#include namespace llarp { namespace utp { - using namespace std::placeholders; - LinkLayer_ptr NewServer(const SecretKey& routerEncSecret, GetRCFunc getrc, LinkMessageHandler h, SessionEstablishedHandler est, @@ -22,15 +21,14 @@ namespace llarp LinkLayer_ptr NewServerFromRouter(AbstractRouter* r) { - using namespace std::placeholders; return NewServer( - r->encryption(), std::bind(&AbstractRouter::rc, r), - std::bind(&AbstractRouter::HandleRecvLinkMessageBuffer, r, _1, _2), - std::bind(&AbstractRouter::OnSessionEstablished, r, _1), - std::bind(&AbstractRouter::CheckRenegotiateValid, r, _1, _2), - std::bind(&AbstractRouter::Sign, r, _1, _2), - std::bind(&AbstractRouter::OnConnectTimeout, r, _1), - std::bind(&AbstractRouter::SessionClosed, r, _1)); + r->encryption(), util::memFn(&AbstractRouter::rc, r), + util::memFn(&AbstractRouter::HandleRecvLinkMessageBuffer, r), + util::memFn(&AbstractRouter::OnSessionEstablished, r), + util::memFn(&AbstractRouter::CheckRenegotiateValid, r), + util::memFn(&AbstractRouter::Sign, r), + util::memFn(&AbstractRouter::OnConnectTimeout, r), + util::memFn(&AbstractRouter::SessionClosed, r)); } } // namespace utp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 304673721..79658a2e2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -39,6 +39,7 @@ list(APPEND TEST_SRC util/test_llarp_util_ini.cpp util/test_llarp_util_metrics_core.cpp util/test_llarp_util_metrics_types.cpp + util/test_llarp_util_memfn.cpp util/test_llarp_util_object.cpp util/test_llarp_util_printer.cpp util/test_llarp_util_queue_manager.cpp diff --git a/test/util/test_llarp_util_memfn.cpp b/test/util/test_llarp_util_memfn.cpp new file mode 100644 index 000000000..96a7e342f --- /dev/null +++ b/test/util/test_llarp_util_memfn.cpp @@ -0,0 +1,68 @@ +#include + +#include +#include + +using namespace llarp; + +struct Foo +{ + bool + empty() + { + return false; + } + + bool + constEmpty() const + { + return true; + } + + int + arg(int v) + { + return v + 1; + } + + int + constArg(int v) const + { + return v - 1; + } +}; + +TEST(MemFn, call) +{ + Foo foo; + ASSERT_FALSE(util::memFn(&Foo::empty, &foo)()); + ASSERT_TRUE(util::memFn(&Foo::constEmpty, &foo)()); + ASSERT_EQ(11, util::memFn(&Foo::arg, &foo)(10)); + ASSERT_EQ(9, util::memFn(&Foo::constArg, &foo)(10)); + + ASSERT_TRUE(util::memFn(&Foo::constEmpty, foo)()); + ASSERT_EQ(9, util::memFn(&Foo::constArg, foo)(10)); +} + +template < typename T > +class MemFnType : public ::testing::Test +{ +}; + +TYPED_TEST_SUITE_P(MemFnType); + +TYPED_TEST_P(MemFnType, Smoke) +{ + TypeParam foo; + ASSERT_TRUE(util::memFn(&Foo::constEmpty, foo)()); + ASSERT_TRUE(util::memFn(&Foo::constEmpty, &foo)()); +} + +REGISTER_TYPED_TEST_SUITE_P(MemFnType, Smoke); + +// clang-format off +using MemFnTypes = ::testing::Types< + Foo, const Foo>; + +INSTANTIATE_TYPED_TEST_SUITE_P(MemFn, MemFnType, MemFnTypes); +// clang-format on diff --git a/test/util/test_llarp_util_traits.cpp b/test/util/test_llarp_util_traits.cpp index 4108acea4..0d234e770 100644 --- a/test/util/test_llarp_util_traits.cpp +++ b/test/util/test_llarp_util_traits.cpp @@ -152,3 +152,30 @@ using SelectTypes = ::testing::Types< INSTANTIATE_TYPED_TEST_SUITE_P(traits, Select, SelectTypes); // clang-format on + +template < typename T > +class IsPointy : public ::testing::Test +{ +}; + +TYPED_TEST_SUITE_P(IsPointy); + +TYPED_TEST_P(IsPointy, Smoke) +{ + bool expected = std::tuple_element_t< 1, TypeParam >::value; + bool result = + traits::is_pointy< std::tuple_element_t< 0, TypeParam > >::value; + ASSERT_EQ(expected, result); +} + +REGISTER_TYPED_TEST_SUITE_P(IsPointy, Smoke); + +// clang-format off +using PointerTypes = ::testing::Types< + std::tuple< int *, std::true_type >, + std::tuple< int, std::integral_constant< bool, false > >, + std::tuple< std::shared_ptr, std::true_type >, + std::tuple< std::unique_ptr, std::true_type > +>; +INSTANTIATE_TYPED_TEST_SUITE_P(traits, IsPointy, PointerTypes); +// clang-format on