c++11 быстрый делегат
От: Barbar1an Украина  
Дата: 15.07.17 11:28
Оценка:
Нашел в инетах обновленную версию быстрых делегатов, но в VS2015 скомпилить ее не могу, с++ в ней всё поддерживает что нужно?

#pragma once
#ifndef DELEGATE_HPP
# define DELEGATE_HPP

#include <cassert>

#include <memory>

#include <new>

#include <type_traits>

#include <utility>

template <typename T> class delegate;

template<class R, class ...A>
class delegate<R (A...)>
{
  using stub_ptr_type = R (*)(void*, A&&...);

  delegate(void* const o, stub_ptr_type const m) noexcept :
    object_ptr_(o),
    stub_ptr_(m)
  {
  }

public:
  delegate() = default;

  delegate(delegate const&) = default;

  delegate(delegate&&) = default;

  delegate(::std::nullptr_t const) noexcept : delegate() { }

  template <class C, typename =
    typename ::std::enable_if< ::std::is_class<C>{}>::type>
  explicit delegate(C const* const o) noexcept :
    object_ptr_(const_cast<C*>(o))
  {
  }

  template <class C, typename =
    typename ::std::enable_if< ::std::is_class<C>{}>::type>
  explicit delegate(C const& o) noexcept :
    object_ptr_(const_cast<C*>(&o))
  {
  }

  template <class C>
  delegate(C* const object_ptr, R (C::* const method_ptr)(A...))
  {
    *this = from(object_ptr, method_ptr);
  }

  template <class C>
  delegate(C* const object_ptr, R (C::* const method_ptr)(A...) const)
  {
    *this = from(object_ptr, method_ptr);
  }

  template <class C>
  delegate(C& object, R (C::* const method_ptr)(A...))
  {
    *this = from(object, method_ptr);
  }

  template <class C>
  delegate(C const& object, R (C::* const method_ptr)(A...) const)
  {
    *this = from(object, method_ptr);
  }

  template <
    typename T,
    typename = typename ::std::enable_if<
      !::std::is_same<delegate, typename ::std::decay<T>::type>{}
    >::type
  >
  delegate(T&& f) :
    store_(operator new(sizeof(typename ::std::decay<T>::type)),
      functor_deleter<typename ::std::decay<T>::type>),
    store_size_(sizeof(typename ::std::decay<T>::type))
  {
    using functor_type = typename ::std::decay<T>::type;

    new (store_.get()) functor_type(::std::forward<T>(f));

    object_ptr_ = store_.get();

    stub_ptr_ = functor_stub<functor_type>;

    deleter_ = deleter_stub<functor_type>;
  }

  delegate& operator=(delegate const&) = default;

  delegate& operator=(delegate&&) = default;

  template <class C>
  delegate& operator=(R (C::* const rhs)(A...))
  {
    return *this = from(static_cast<C*>(object_ptr_), rhs);
  }

  template <class C>
  delegate& operator=(R (C::* const rhs)(A...) const)
  {
    return *this = from(static_cast<C const*>(object_ptr_), rhs);
  }

  template <
    typename T,
    typename = typename ::std::enable_if<
      !::std::is_same<delegate, typename ::std::decay<T>::type>{}
    >::type
  >
  delegate& operator=(T&& f)
  {
    using functor_type = typename ::std::decay<T>::type;

    if ((sizeof(functor_type) > store_size_) || !store_.unique())
    {
      store_.reset(operator new(sizeof(functor_type)),
        functor_deleter<functor_type>);

      store_size_ = sizeof(functor_type);
    }
    else
    {
      deleter_(store_.get());
    }

    new (store_.get()) functor_type(::std::forward<T>(f));

    object_ptr_ = store_.get();

    stub_ptr_ = functor_stub<functor_type>;

    deleter_ = deleter_stub<functor_type>;

    return *this;
  }

  template <R (* const function_ptr)(A...)>
  static delegate from() noexcept
  {
    return { nullptr, function_stub<function_ptr> };
  }

  template <class C, R (C::* const method_ptr)(A...)>
  static delegate from(C* const object_ptr) noexcept
  {
    return { object_ptr, method_stub<C, method_ptr> };
  }

  template <class C, R (C::* const method_ptr)(A...) const>
  static delegate from(C const* const object_ptr) noexcept
  {
    return { const_cast<C*>(object_ptr), const_method_stub<C, method_ptr> };
  }

  template <class C, R (C::* const method_ptr)(A...)>
  static delegate from(C& object) noexcept
  {
    return { &object, method_stub<C, method_ptr> };
  }

  template <class C, R (C::* const method_ptr)(A...) const>
  static delegate from(C const& object) noexcept
  {
    return { const_cast<C*>(&object), const_method_stub<C, method_ptr> };
  }

  template <typename T>
  static delegate from(T&& f)
  {
    return ::std::forward<T>(f);
  }

  static delegate from(R (* const function_ptr)(A...))
  {
    return function_ptr;
  }

  template <class C>
  using member_pair =
    ::std::pair<C* const, R (C::* const)(A...)>;

  template <class C>
  using const_member_pair =
    ::std::pair<C const* const, R (C::* const)(A...) const>;

  template <class C>
  static delegate from(C* const object_ptr,
    R (C::* const method_ptr)(A...))
  {
    return member_pair<C>(object_ptr, method_ptr);
  }

  template <class C>
  static delegate from(C const* const object_ptr,
    R (C::* const method_ptr)(A...) const)
  {
    return const_member_pair<C>(object_ptr, method_ptr);
  }

  template <class C>
  static delegate from(C& object, R (C::* const method_ptr)(A...))
  {
    return member_pair<C>(&object, method_ptr);
  }

  template <class C>
  static delegate from(C const& object,
    R (C::* const method_ptr)(A...) const)
  {
    return const_member_pair<C>(&object, method_ptr);
  }

  void reset() { stub_ptr_ = nullptr; store_.reset(); }

  void reset_stub() noexcept { stub_ptr_ = nullptr; }

  void swap(delegate& other) noexcept { ::std::swap(*this, other); }

  bool operator==(delegate const& rhs) const noexcept
  {
    return (object_ptr_ == rhs.object_ptr_) && (stub_ptr_ == rhs.stub_ptr_);
  }

  bool operator!=(delegate const& rhs) const noexcept
  {
    return !operator==(rhs);
  }

  bool operator<(delegate const& rhs) const noexcept
  {
    return (object_ptr_ < rhs.object_ptr_) ||
      ((object_ptr_ == rhs.object_ptr_) && (stub_ptr_ < rhs.stub_ptr_));
  }

  bool operator==(::std::nullptr_t const) const noexcept
  {
    return !stub_ptr_;
  }

  bool operator!=(::std::nullptr_t const) const noexcept
  {
    return stub_ptr_;
  }

  explicit operator bool() const noexcept { return stub_ptr_; }

  R operator()(A... args) const
  {
//  assert(stub_ptr);
    return stub_ptr_(object_ptr_, ::std::forward<A>(args)...);
  }

private:
  friend struct ::std::hash<delegate>;

  using deleter_type = void (*)(void*);

  void* object_ptr_;
  stub_ptr_type stub_ptr_{};

  deleter_type deleter_;

  ::std::shared_ptr<void> store_;
  ::std::size_t store_size_;

  template <class T>
  static void functor_deleter(void* const p)
  {
    static_cast<T*>(p)->~T();

    operator delete(p);
  }

  template <class T>
  static void deleter_stub(void* const p)
  {
    static_cast<T*>(p)->~T();
  }

  template <R (*function_ptr)(A...)>
  static R function_stub(void* const, A&&... args)
  {
    return function_ptr(::std::forward<A>(args)...);
  }

  template <class C, R (C::*method_ptr)(A...)>
  static R method_stub(void* const object_ptr, A&&... args)
  {
    return (static_cast<C*>(object_ptr)->*method_ptr)(
      ::std::forward<A>(args)...);
  }

  template <class C, R (C::*method_ptr)(A...) const>
  static R const_method_stub(void* const object_ptr, A&&... args)
  {
    return (static_cast<C const*>(object_ptr)->*method_ptr)(
      ::std::forward<A>(args)...);
  }

  template <typename>
  struct is_member_pair : std::false_type { };

  template <class C>
  struct is_member_pair< ::std::pair<C* const,
    R (C::* const)(A...)> > : std::true_type
  {
  };

  template <typename>
  struct is_const_member_pair : std::false_type { };

  template <class C>
  struct is_const_member_pair< ::std::pair<C const* const,
    R (C::* const)(A...) const> > : std::true_type
  {
  };

  template <typename T>
  static typename ::std::enable_if<
    !(is_member_pair<T>{} ||
    is_const_member_pair<T>{}),
    R
  >::type
  functor_stub(void* const object_ptr, A&&... args)
  {
    return (*static_cast<T*>(object_ptr))(::std::forward<A>(args)...);
  }

  template <typename T>
  static typename ::std::enable_if<
    is_member_pair<T>{} ||
    is_const_member_pair<T>{},
    R
  >::type
  functor_stub(void* const object_ptr, A&&... args)
  {
    return (static_cast<T*>(object_ptr)->first->*
      static_cast<T*>(object_ptr)->second)(::std::forward<A>(args)...);
  }
};

namespace std
{
  template <typename R, typename ...A>
  struct hash<::delegate<R (A...)> >
  {
    size_t operator()(::delegate<R (A...)> const& d) const noexcept
    {
      auto const seed(hash<void*>()(d.object_ptr_));

      return hash<typename ::delegate<R (A...)>::stub_ptr_type>()(
        d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    }
  };
}

#endif // DELEGATE_HPP


'delegate<R(A...)>::is_member_pair<<unnamed-symbol>>': no appropriate default constructor available
'delegate<R(A...)>::is_const_member_pair<<unnamed-symbol>>': no appropriate default constructor available
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Re: c++11 быстрый делегат
От: kov_serg Россия  
Дата: 15.07.17 11:51
Оценка: +1
Здравствуйте, Barbar1an, Вы писали:

B>Нашел в инетах обновленную версию быстрых делегатов, но в VS2015 скомпилить ее не могу, с++ в ней всё поддерживает что нужно?

Ради чего вся эта порнография?
Re[2]: c++11 быстрый делегат
От: Barbar1an Украина  
Дата: 15.07.17 15:02
Оценка: :)
Здравствуйте, kov_serg, Вы писали:

_>Здравствуйте, Barbar1an, Вы писали:


B>>Нашел в инетах обновленную версию быстрых делегатов, но в VS2015 скомпилить ее не могу, с++ в ней всё поддерживает что нужно?

_>Ради чего вся эта порнография?

ну кода в 10 раз меньше и можно подписывать лямбды, и в 1.5 раза быстрее std::function
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Re[3]: c++11 быстрый делегат
От: T4r4sB Россия  
Дата: 15.07.17 16:48
Оценка:
Здравствуйте, Barbar1an, Вы писали:

_>>Ради чего вся эта порнография?


B>ну кода в 10 раз меньше


Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re: c++11 быстрый делегат
От: prezident.mira Россия  
Дата: 16.07.17 02:06
Оценка:
Здравствуйте, Barbar1an, Вы писали:

B>'delegate<R(A...)>::is_member_pair<<unnamed-symbol>>': no appropriate default constructor available

B>'delegate<R(A...)>::is_const_member_pair<<unnamed-symbol>>': no appropriate default constructor available

Можно минимальный пример кода?
Re[2]: c++11 быстрый делегат
От: kov_serg Россия  
Дата: 16.07.17 07:13
Оценка: 6 (1)
Здравствуйте, prezident.mira, Вы писали:

PM>Здравствуйте, Barbar1an, Вы писали:


B>>'delegate<R(A...)>::is_member_pair<<unnamed-symbol>>': no appropriate default constructor available

B>>'delegate<R(A...)>::is_const_member_pair<<unnamed-symbol>>': no appropriate default constructor available

PM>Можно минимальный пример кода?


https://stackoverflow.com/questions/35912409/impossibly-fast-delegate-in-c11-on-msvc14
Re[3]: c++11 быстрый делегат
От: prezident.mira Россия  
Дата: 16.07.17 07:16
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Здравствуйте, prezident.mira, Вы писали:


PM>>Здравствуйте, Barbar1an, Вы писали:


B>>>'delegate<R(A...)>::is_member_pair<<unnamed-symbol>>': no appropriate default constructor available

B>>>'delegate<R(A...)>::is_const_member_pair<<unnamed-symbol>>': no appropriate default constructor available

PM>>Можно минимальный пример кода?


_>https://stackoverflow.com/questions/35912409/impossibly-fast-delegate-in-c11-on-msvc14


Ага, я тоже сразу подумал про то, что надо попробовать заменить создание объекта на обращение к ::value.
Re[3]: c++11 быстрый делегат
От: Barbar1an Украина  
Дата: 16.07.17 08:12
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Здравствуйте, prezident.mira, Вы писали:


PM>>Здравствуйте, Barbar1an, Вы писали:


B>>>'delegate<R(A...)>::is_member_pair<<unnamed-symbol>>': no appropriate default constructor available

B>>>'delegate<R(A...)>::is_const_member_pair<<unnamed-symbol>>': no appropriate default constructor available

PM>>Можно минимальный пример кода?


_>https://stackoverflow.com/questions/35912409/impossibly-fast-delegate-in-c11-on-msvc14


вай пасиба)
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Re: c++11 быстрый делегат
От: Barbar1an Украина  
Дата: 16.07.17 15:21
Оценка:
похоже я погорячился, там при создании память выделяется поэтому этот вариант делегатов сильно тормознее по сравнению с оригиналом
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Re: c++11 быстрый делегат
От: Дрободан Фрилич СССР  
Дата: 17.07.17 14:21
Оценка:
Barbar1an:

template<class R, class ...A>
class delegate<R (A...)>


Нераспарсил, а что за параметр R (A...) у шаблона delegate?
Функция-не функция (нет возвращаемого значения).
Что это?
Re[2]: c++11 быстрый делегат
От: night beast СССР  
Дата: 17.07.17 14:23
Оценка:
Здравствуйте, Дрободан Фрилич, Вы писали:

ДФ>
ДФ>template<class R, class ...A>
ДФ>class delegate<R (A...)>
ДФ>


ДФ>Нераспарсил, а что за параметр R (A...) у шаблона delegate?

ДФ>Функция-не функция (нет возвращаемого значения).
ДФ>Что это?

функция, возвращающая R
Re[3]: c++11 быстрый делегат
От: Дрободан Фрилич СССР  
Дата: 17.07.17 14:29
Оценка: +1
night beast:

ДФ>>
ДФ>>template<class R, class ...A>
ДФ>>class delegate<R (A...)>
ДФ>>


ДФ>>Нераспарсил, а что за параметр R (A...) у шаблона delegate?

ДФ>>Функция-не функция (нет возвращаемого значения).
ДФ>>Что это?

NB>функция, возвращающая R

В мое время писали как-то так R (*)(A...).
Я что-то упустил в плюсах. Буду навёрстывать...
Re[4]: c++11 быстрый делегат
От: uzhas Ниоткуда  
Дата: 17.07.17 14:44
Оценка:
Здравствуйте, Дрободан Фрилич, Вы писали:

ДФ>Я что-то упустил в плюсах. Буду навёрстывать...


начинай отсюда: http://rsdn.org/forum/humour/6830080.flat
Автор: D. Mon
Дата: 05.07.17
Re[4]: c++11 быстрый делегат
От: night beast СССР  
Дата: 17.07.17 14:47
Оценка:
Здравствуйте, Дрободан Фрилич, Вы писали:

NB>>функция, возвращающая R

ДФ>В мое время писали как-то так R (*)(A...).

это указатель на функцию.

ДФ>Я что-то упустил в плюсах. Буду навёрстывать...


typedef R fun_type(int);
typedef R (*fun_pointer)(int);
Re[2]: c++11 быстрый делегат
От: Barbar1an Украина  
Дата: 17.07.17 15:27
Оценка:
Здравствуйте, Barbar1an, Вы писали:

B>похоже я погорячился, там при создании память выделяется поэтому этот вариант делегатов сильно тормознее по сравнению с оригиналом


в общем вот бенчмарки

FastDelegate ctor: 0.001089 (не поддерживает лямбды)
C++14 Delegate ctor (my adaptive allocator): 0.012582
C++14 Delegate ctor (new allocator): 0.207923

FastDelegate call: 0.083223 (не поддерживает лямбды)
C++14 Delegate call (my adaptive allocator): 0.084994
C++14 Delegate call (new allocator): 0.083777

из них видно что время создания у с++14 с вы делением памяти через new ужасно долгое
я сделал умнее, но все равно в 12 раз медленнее оригинала(умнее значит что мы храним 8 байт которые использем для хранения данных если они помещаются или для хранения указателя на память в куче)

скорость вызова везде похожая
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Отредактировано 17.07.2017 15:27 Barbar1an . Предыдущая версия .
Re: c++11 быстрый делегат
От: PM  
Дата: 17.07.17 20:35
Оценка:
Здравствуйте, Barbar1an, Вы писали:

B>Нашел в инетах обновленную версию быстрых делегатов, но в VS2015 скомпилить ее не могу, с++ в ней всё поддерживает что нужно?


B>//здесь был код


А чем это принципиально отличается от `std::function`? На первый взгляд то же самое стирание типов с динамическим выделением памяти. Если проблема действительно в динамическом выделении памяти, то попробуйте какую-нибудь из реализаций `std::function` с предвыделенным буфером внутри:

https://rsdn.org/forum/cpp.applied/6598592
Автор: niXman
Дата: 01.11.16

https://rsdn.org/forum/cpp/5737241
Автор: sokel
Дата: 12.08.14
Re: c++11 быстрый делегат
От: lxa http://aliakseis.livejournal.com
Дата: 28.07.17 16:41
Оценка:
Встречный вопрос. Есть такие делегаты:

// http://blog.coldflake.com/posts/C++-delegates-on-steroids/

#include <utility>

template<typename return_type, typename... params>
struct DelegateScope
{
    template <class T, return_type(T::*TMethod)(params...)>
    class Delegate
    {
    public:
        explicit Delegate(T* callee)
            : fpCallee(callee)
        {}
        //return_type operator()(params... xs) const
        //{
        //    return (fpCallee->*TMethod)(xs...);
        //}
        template <typename... Args>
        return_type operator()(Args&&... xs) const
        {
            return (fpCallee->*TMethod)(std::forward<Args>(xs)...);
        }

        bool operator == (const Delegate& other) const
        {
            return fpCallee == other.fpCallee;
        }

        bool operator != (const Delegate& other) const
        {
            return fpCallee != other.fpCallee;
        }

    private:
        T* fpCallee;
    };
};

template<typename T, typename return_type, typename... params>
struct DelegateMaker
{
    template<return_type(T::*foo)(params...)>
    inline static auto Bind(T* o)
    {
        return DelegateScope<return_type, params...>::Delegate<T, foo>(o);
    }
};

template<typename T, typename return_type, typename... params>
DelegateMaker<T, return_type, params... >
makeDelegate(return_type(T::*)(params...))
{
    return DelegateMaker<T, return_type, params...>();
}

#define MAKE_DELEGATE(foo, thisPrt) (makeDelegate(foo).Bind<foo>(thisPrt))


Они очень удобно сочетаются с boost::signals2. Можно писать так:
    m_pDoc->framePositionChanged.connect(MAKE_DELEGATE(&CDialogBarPlayerControl::onFramePositionChanged, this));
    m_pDoc->totalTimeUpdated.connect(MAKE_DELEGATE(&CDialogBarPlayerControl::onTotalTimeUpdated, this));
    m_pDoc->currentTimeUpdated.connect(MAKE_DELEGATE(&CDialogBarPlayerControl::onCurrentTimeUpdated, this));
...
    m_pDoc->framePositionChanged.disconnect(MAKE_DELEGATE(&CDialogBarPlayerControl::onFramePositionChanged, this));
    m_pDoc->totalTimeUpdated.disconnect(MAKE_DELEGATE(&CDialogBarPlayerControl::onTotalTimeUpdated, this));
    m_pDoc->currentTimeUpdated.disconnect(MAKE_DELEGATE(&CDialogBarPlayerControl::onCurrentTimeUpdated, this));


Только интересно, можно ли обойтись без макроса?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.