Григорий Демченко, Универсальный адаптер
TRANSCRIPT
YT
Универсальный адаптер
Григорий Демченко
+ Сервис
4
План
▌Поиспользовать продвинутые шаблоны
▌Поиспользовать продвинутые макросы
Постановка задачи
6
Умный мьютекс
Статья: https://habrahabr.ru/post/184436/
struct Data { int get() const { return val_; } void set(int v) { val_ = v; }private: int val_ = 0;}; SmartMutex<Data> d;d->set(4);std::cout << d->get() << std::endl;
7
Проблема №1
std::cout << d->get() << std::endl;
8
Проблема №2
int sum(const SmartMutex<Data>& x, const SmartMutex<Data>& y) { return x->get() + y->get();}
Решение
10
Адаптерusing Lock = std::unique_lock<std::mutex>; struct DataLocked { int get() const { Lock _{mutex_}; return data_.get(); } void set(int v) { Lock _{mutex_}; data_.set(v); }private: mutable std::mutex mutex_; Data data_;};
11
Обобщенный адаптерtemplate<typename T_base>struct DataAdapter : T_base { void set(int v) { this->call([v](Data& data) { data.set(v); }); }}; struct MutexBase {protected: template<typename F> void call(F f) { Lock _{mutex_}; f(data_); }private: Data data_; std::mutex mutex_;};
12
Обобщение обобщенного адаптера
template<typename T_base>struct DataAdapter : T_base { void set(int v) { this->call([](Data& data, int v) { data.set(v); }, v); }};
13
Обобщение BaseLockertemplate<typename T_base, typename T_locker>struct BaseLocker : T_base {protected: template<typename F, typename... V> auto call(F f, V&&... v) { Lock _{lock_}; return f(static_cast<T_base&>(*this), std::forward<V>(v)...); }private: T_locker lock_;};
14
Обобщение обобщенного обобщенного адаптераvoid set(int v) { this->call([](Data& data, int v) { data.set(v); }, v);}
template<typename... V>auto set(V&&... v) { return this->call([](auto& t, auto&&... x) { return t.set(std::forward<???>(x)...); }, std::forward<V>(v)...);}
Какой тип?
15
Обобщение обобщенного обобщенного адаптераvoid set(int v) { this->call([](Data& data, int v) { data.set(v); }, v);}
template<typename... V>auto set(V&&... v) { return this->call([](auto& t, auto&&... x) { return t.set(std::forward<decltype(x)>(x)...); }, std::forward<V>(v)...);}
16
Универсальный адаптер#define DECL_FN_ADAPTER(D_name) \ template<typename... V> \ auto D_name(V&&... v) { \ return this->call([](auto& t, auto&&... x) { \ return t.D_name(std::forward<decltype(x)>(x)...);\ }, std::forward<V>(v)...); \ } #define DECL_FN_ADAPTER_ITER(D_r, D_data, D_elem) \ DECL_FN_ADAPTER(D_elem) #define DECL_ADAPTER(D_type, ...) \ template<typename T_base> \ struct Adapter<D_type, T_base> : T_base \ { \ BOOST_PP_LIST_FOR_EACH(DECL_FN_ADAPTER_ITER, , \ BOOST_PP_TUPLE_TO_LIST((__VA_ARGS__))) \ };
Применение
18
Мьютекс
DECL_ADAPTER(Data, get, set) // сахарокtemplate<typename T, typename T_locker = std::mutex, typename T_base = T>using AdaptedLocked = Adapter< T, BaseLocker<T_base, T_locker>>; using DataLocked = AdaptedLocked<Data>;
19
Адаптированный умный указательtemplate<typename T>struct BaseShared{protected: template<typename F, typename... V> auto call(F f, V&&... v) { return f(*shared_, std::forward<V>(v)...); }private: std::shared_ptr<T> shared_;}; template<typename T, typename T_base = T>using AdaptedShared = Adapter<T, BaseShared<T_base>>;
20
Адаптированный умный указатель
using DataRefCounted = AdaptedShared<Data>; DataRefCounted data;data.set(42);
21
Комбинирование адаптеров
template<typename T, typename T_locker = std::mutex, typename T_base = T>using AdaptedSharedLocked = AdaptedShared< T, AdaptedLocked<T, T_locker, T_base>>;
using DataTotallyShared = AdaptedSharedLocked<Data>;
DataTotallyShared data;// ...auto newData = data;newData.set(42);assert(data.get() == 42);
22
Ленивость
struct Obj { Obj(); void action();};DECL_ADAPTER(Obj, action) Obj obj; // вызов Obj::Objobj.action(); // вызов actionobj.action(); // вызов action AdaptedLazy<Obj> lazyObj; // без Obj::ObjlazyObj.action(); // вызов Obj::Obj и actionlazyObj.action(); // вызов action
23
Реализация ленивостиtemplate<typename T>struct BaseLazy { template<typename... V> BaseLazy(V&&... v) { state_ = [v...] { return T{std::move(v)...}; }; }protected: template<typename F, typename... V> auto call(F f, V&&... v) { auto* t = boost::get<T>(&state_); if (t == nullptr) { state_ = boost::get<std::function<T()>>(state_)(); t = boost::get<T>(&state_); } return f(*t, std::forward<V>(v)...); }private: boost::variant<std::function<T()>, T> state_;};
24
Batchingtemplate<typename T_base>struct BaseBatch : T_base { void execute() { for (auto&& action: actions_) { action(); } actions_.clear(); }protected: template<typename F, typename... V> auto call(F f, V&&... v) { actions_.push_back([this, f, v...] { f(*this, v...); }); }private: std::vector<std::function<void()>> actions_;};
25
Disk Batching
struct Disk { void write(const Buffer& buffer);}; AdaptedBatch<Disk> disk; disk.write(buf1);disk.write(buf2);disk.execute(); // запишет buf1 и buf2
26
Интегральный пример
DECL_ADAPTER(Disk, write) struct DiskExecute;DECL_ADAPTER(DiskExecute, write, execute) AdaptedLazy<DiskExecute, AdaptedShared<DiskExecute, AdaptedLocked<DiskExecute, AdaptedBatch<Disk>>>> disk; disk.write(buf1); // лениво создаст diskdisk.write(buf2);disk.execute(); // запишет buf1 и buf2
27
Накладные расходы
▌Тестовый класс
template<typename T>struct BaseValue : T {protected: template<typename F, typename... V> auto call(F f, V&&... v) { return f(t, std::forward<V>(v)...); }};
struct X { int on(int v) { return v + 1; }};
28
Сравнение
// эталонная функцияint f1(int v) { X x; return x.on(v);}
// с адаптеромint f2(int v) { Adapter<X, BaseValue<X>> x; return x.on(v);}
29
Результаты▌GCC 4.9.2:
▌Clang 3.5.1:
f1(int): leal 1(%rdi), %eax retf2(int): leal 1(%rdi), %eax ret
f1(int): # @f1(int) leal 1(%rdi), %eax retq f2(int): # @f2(int) leal 1(%rdi), %eax retq
30
Выводы
▌Универсальный способ обернуть объект и придать ему новое поведение.
▌Комбинация базовых примитивов.
▌Расширяемость.
▌Разделение вызова и изменения поведения.
31
Дальнейшие направления развития
▌Многопоточные примитивы и асинхронность.
▌Транзакционность.
▌Распределенность и консистентность.
Григорий Демченко[email protected]
Умный мьютекс:https://habrahabr.ru/post/184436/https://video.yandex.ru/users/ya-events/view/2931
Код: https://github.com/gridem/GodAdapter
РГ21 https://stdcpp.ru
│ Вопросы?