Create util::MemFn and memFn to make binding callbacks easier

pull/638/head
Michael 5 years ago
parent 95b28a9fb5
commit 3822fe2341
No known key found for this signature in database
GPG Key ID: 2D51757B47E2434C

@ -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

@ -0,0 +1 @@
#include <util/memfn.hpp>

@ -0,0 +1,91 @@
#ifndef LLARP_UTIL_MEMFN
#define LLARP_UTIL_MEMFN
#include <util/memfn_traits.hpp>
#include <util/object.hpp>
#include <util/traits.hpp>
#include <functional>
#include <utility>
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

@ -0,0 +1 @@
#include <util/memfn_traits.hpp>

@ -0,0 +1,107 @@
#ifndef LLARP_UTIL_MEMFN_TRAITS
#define LLARP_UTIL_MEMFN_TRAITS
#include <util/object.hpp>
#include <util/traits.hpp>
#include <functional>
#include <utility>
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

@ -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 >

@ -1,6 +1,8 @@
#ifndef LLARP_TRAITS_HPP
#define LLARP_TRAITS_HPP
#include <absl/meta/type_traits.h>
#include <cstddef>
#include <type_traits>
#include <utility>
@ -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 >

@ -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

@ -0,0 +1,68 @@
#include <util/memfn.hpp>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
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

@ -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<int>, std::true_type >,
std::tuple< std::unique_ptr<int>, std::true_type >
>;
INSTANTIATE_TYPED_TEST_SUITE_P(traits, IsPointy, PointerTypes);
// clang-format on

Loading…
Cancel
Save