LINUX.ORG.RU

Сообщения Cupper

 

Generic comparator with templated accessor to elements

Провет, я хотел бы наити стандартный способ (СТЛ) сортировки массива пар, с возвожностью специализации способа сравнениа елементов

Что то вроде вот такого

template <class P>
struct Pair2First {
    const typename P::first_type& operator() (const P &p) { return p.first; }
};

template <class P>
struct Pair2Second {
    const typename P::second_type& operator() (const P &p) { return p.second; }
};

template <class Type, typename Accessor>
struct Greater {
    typedef Type first_argument_type;
    typedef Type second_argument_type;
    typedef bool result_type;
    
    bool operator() (const Type& lhs, const Type& rhs) const {
        return accessor(lhs) > accessor(rhs);
    }
    
    Accessor accessor;
};

typedef pair<int, double> PairX;

int main()
{
    vector<PairX> vec = {
        make_pair(9, 6.5),
        make_pair(3, 6.3),
        make_pair(5, 6.9),
    };
    
    PairX p1 = make_pair(1, 2.0);
    PairX p2 = make_pair(2, 1.0);
    
    cout << Greater<PairX, Pair2First<PairX>>()(p1, p2) << endl;
    
    stable_sort(vec.begin(), vec.end(), Pair2First<PairX>>);
}

 ,

Cupper
()

Thunderbird - Quick action (aka Outlook)

Привет. Подскажите как можно сделать аналог «Quick Action» в Thunderbird.

Чего нужно добится: Появисаль отдельная кнопочка для ваполнения заданного деиствия для выбранного письма.

Действие:

1. отправить письмо как аттач на указанний адрес, с заданной темой и телом сообщениыя.

2. переместить тред в специальную папку.

SmartTemplate4 не умеет этого.

 

Cupper
()

CSS box model - перекрытие элементов и неожиданные отспуты

Ознакомился с данной концепцией, вроде все понятно.

навоял пример, http://jsfiddle.net/fx5t4/ и понял, что видать упустил нехилый кусок понимания.

Из этого кода у меня возникают следующие вопросы:

1. Почему между границами двух span'ов есть пространство? Хотя указан margin: 0 на обоих.

2. Почему div не растянулся в сооветсвии с размерами вложеных span'ов? Ему ни padding ни border ни почем.

Можно даже не разжевывать, хотя бы линк на материал где объясняется именно это, а не то, что такое border/margin/padding. Часа 2 уже гуглю, так ничего и не выгуглил.

Спасибо.

Перемещено beastie из development

 ,

Cupper
()

не работает nav-collapse collapse

Привет, и снова я.

Использую элемент nav-collapse collapse из bootstrap для шапки сайта. При уменьшении окна, все как надо сворачивается, кнопка появляется, но она не работает. Пробовал гуглить, нашел два несовсе понятных решения, заключавшиеся в переименовании некоторых элементов или удалении некоторого тега, но они только разваливают шапку и все равно не работают.

Собстно сам сайт тут http://rango.pythonanywhere.com

А вот так выглядит этот элемент

<div class="navbar navbar-inverse navbar-fixed-top">
          <div class="navbar-inner">
              <div class="container">
                  <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
                      <span class="icon-bar"></span>
                      <span class="icon-bar"></span>
                      <span class="icon-bar"></span>
                  </button>
                  <a class="brand" href="/rango/">Rango</a>

                  <div class="nav-collapse collapse">
                      <ul class="nav pull-right">
                          
                          <li><a href="/rango/profile/">Welcome, <strong>rango</strong>!</a></li>
                          <li><a href="/rango/logout/">Logout</a></li>
                          
                      </ul>
                      <ul class="nav">
                          
                          <li><a href="/rango/add_category/">Add Category</a></li>
                          
                          <li><a href="/rango/about/">About</a></li>
                      </ul>
                  </div>
                  <!--/.nav-collapse -->
              </div>
          </div>
      </div>

 ,

Cupper
()

JavaScript функция для элементов из списка <ol></ol>

Привет, есть вот такой список в HTML

( читать дальше... )

генерируется шаблонизатором, элементов <li> в списке может быть сколько угодно. В каждой строке есть кнопка с id=«auto_add_page» (я могу сделать идентификатор уникальный для каждой кнопки если нужно) и некоторой доп. информацией.

На каждую кнопку вашается JS обработчик, который делает GET запрос с информацией которая вытаскивается из соотвествующего батона (типо AJAX).

сейчас js функция выглядит так

    $('#auto_add_page').click(function() {
    	var catid, title, url;
    	catid = $(this).attr("data-catid");
    	title = $(this).attr("data-title");
    	url = $(this).attr("data-url");
    	$.get('/rango/auto_add_page/', 
    		{catid: catid, title: title, url: url},
    		function(data){
    			$('#pages').html(data);
    		});
    });
Это работает только для первой кнопки. Как сделать так что бы этаже функция была забиндена и на все остальные кнопки. Напрщивается, что у них должны быть уникальные ID, но как тогда описа'ть JS функцию?

 , ,

Cupper
()

CSS адаптивная верстка

Пытаюсь состряпать вот такой макет

http://jsfiddle.net/rRm7k/439/

но я хочу что бы элемент Footer был всегда прилеплен к низу экрана. А l_sidebar, main и r_sidebar были растянуты между Header и Footer.

При этом размер Header/Footer должен задаваться в px. А так же размер L/R Sidebar тоже в px. Хотя это уже и так сохранено, но я это к тому, что бы не делали жесткую верстку, она должна растягиваться для любой экран.

Спасибо.

Перемещено leave из development

 ,

Cupper
()

Удаленный рабочий стол без IP

Подскажите пожалуйста софт для удаленного рабочего стола, но что бы адрес определялся внешними средствами а не прямо по IP. C Ubuntu 12.04 есть встроеная вича, но вот в 14.04 ее уже нету. Чем можно заменить?

Спасибо.

 

Cupper
()

Шаблонный класс из шаблонной функции

Что то я не понимаю что я делаю не так :(

#include <iostream>

using namespace std;

template <class T>
class Task
{
public:
    Task(T t){}    
};

template <class T>
Task<T> make_task(T t)
{
    return Task(t);
}

int main()
{
   cout << "Hello World" << endl; 
   
   make_task(1);
   
   return 0;
}
main.cpp: In function ‘Task<T> make_task(T)’:
main.cpp:14:16: error: missing template arguments before ‘(’ token
     return Task(t);
                ^

Т.е. можно только вот так?

template <class T>
Task<T> make_task(T t)
{
    Task<T> tmp(t);
    return tmp;
}

Cupper
()

Произвольный порядок списка инициализации шаблона

У меня есть два типа понтейнера которые принимают по 3 шаблонных параметра

template<class T, class Deferred, class Deadline>
struct prio_container;

template<class T, class Deferred, class Deadline>
struct queue_container;
Тип T - это элемент контейнера.

Deferred и Deadline это плагины, которые расширяют функционал. Все делается без палиморфизма, исключительно на этапе компиляции (статический полиморфизм).

Я хочу абстрагироваться от конкретных реализаций и сделать интерфейс, который бы через указание шаблонных параметров выбирал нужную специализацию. Притом даже сам тип контейнера для пользователя выглядил бы как подключаемый плагин. А так же отвязаться от порядка задания параметром шаблона, и необходимости указывать их все, даже если они не используются. Вот пример того что я пытаюсь сделать.

template<class T, 
         class Plugin1 = disable_plugin,
         class Plugin2 = disable_plugin,
         class Plugin3 = disable_plugin>
struct container;

Я смог додуматься только до перечисление всех возможных специализаций. Но это издец как муторно. и если появятся новые плагины то пиши пропало, число комбинаций перевалит за разумный предел.

#include <iostream>
#include <string>

using namespace std;

#define static_type(name) \
    static const std::string& type() \
    { \
        static std::string type_(name); \
        return type_; \
    } \

struct prio_plugin;
struct dis_prio_plugin;

struct deferred_plugin
{ static_type("deferred"); };

struct deadline_plugin
{ static_type("deadline"); };

struct disable_plugin
{ static_type("disable"); };

template<class T, class Deferred, class Deadline>
struct prio_container
{
    static const std::string& type()
    {
        static std::string type_("prio_container<" + 
                                    Deferred::type() + ", " +
                                    Deadline::type() + ">");
        return type_;
    }
};

template<class T, class Deferred, class Deadline>
struct queue_container
{
    static const std::string& type()
    {
        static std::string type_("queue_container<" + 
                                    Deferred::type() + ", " +
                                    Deadline::type() + ">");
        return type_;
    }
};

template<class T, 
         class Plugin1 = disable_plugin,
         class Plugin2 = disable_plugin,
         class Plugin3 = disable_plugin>
struct container;

template<class T, 
         class Plugin1,
         class Plugin2>
struct container<T, prio_plugin, Plugin1, Plugin2>
{
    typedef prio_container<T, Plugin1, Plugin2> type;
};

template<class T, class DisableDeadline>
struct container<T, prio_plugin, deferred_plugin, DisableDeadline>
{
    typedef prio_container<T, deferred_plugin, DisableDeadline> type;
};

template<class T, class DisableDeferred>
struct container<T, prio_plugin, deadline_plugin, DisableDeferred>
{
    typedef prio_container<T, DisableDeferred, deadline_plugin> type;
};

template<class T>
struct container<T, prio_plugin, deadline_plugin, deferred_plugin>
{
    typedef prio_container<T, deferred_plugin, deadline_plugin> type;
};

template<class T>
struct container<T, prio_plugin, deferred_plugin, deadline_plugin>
{
    typedef prio_container<T, deferred_plugin, deadline_plugin> type;
};



int main()
{
   cout << "Hello World" << endl; 
   
   cout << container<int, prio_plugin>::type::type() << std::endl;
   cout << container<int, prio_plugin, deadline_plugin>::type::type() << std::endl;
   cout << container<int, prio_plugin, deferred_plugin>::type::type() << std::endl;
   cout << container<int, prio_plugin, deferred_plugin, deadline_plugin>::type::type() << std::endl;
   cout << container<int, prio_plugin, deadline_plugin, deferred_plugin>::type::type() << std::endl;
   
   return 0;
}
prio_container<disable, disable>
prio_container<disable, deadline>
prio_container<deferred, disable>
prio_container<deferred, deadline>
prio_container<deferred, deadline>

Cupper
()

condition_variable + timed_mutex

Это возможно? Я не нашел ни одного упоминания как это сделать. Вариант написать свой timed_condition_variable не рассматривается.

 

Cupper
()

Размышление об архитектуре класса/классов

Представьте, что вам нужен класс repository который содержит функцию make(ID& id) (При этом мы не знаем что такое ID, сейчас это шаблонный параметр). Данная функция должна возвращать некоторую сущность A, при этом если в текущий момент еще нет сущности ассоциированной с таким id, то он должен ее создать, а если есть то вернуть ранее созданную.

Очевидно что A это shared_ptr<A>. Задача состоит в том что бы уметь удалять из repository информацию об id и связанного с ним A когда будут удалены все A полученный через make.

В голову приходит идея хранить в repository map<ID, weak_ptr<A> >. Далее нам нужно как то научить A (в деструкторе), обращатся к repository и удалять себя из него.

Тип А, сам по себе, ни как не связан с ID, так и хотелось бы это оставить. Из за этого я не особо понимаю как можно связать A и repository, так как repository это шаблон, а A не знает тип которым инстанцируется этот шаблон (это про ID).

Пока в голову приходит только, хранить в A полсностью сконфигурированный функтор, который знает к кому обратиться и что удалить. Интересует как можно было обойтись без биндеров и функторов, но при это оставить слубую связность между A и repository<ID>.

 

Cupper
()

Утилита для тестирования DNS

Подскажите, как можно потетсить развернутый локально DNS сервер, который не является DNS сервером системы. Т.е. у меня есть просто сервер на определенном порту, который умеет резолвить имена и мне нужно чемто на подобие host стрельнуть в него что бы проверить что он работает.

В идеале что то вроде

host http://www.example.com -p 10053

Cupper
()

User hook на coredump

Как то давно мне приходилось делать автоматическое создание репортов при возникновении coredump нашего приложение. Это делалось внешними средствами системы. Т.е. при возникновении coredump система сперва вызывала мой зарегистрированный скрипт с какими то параметрами, в котором я мог сделать репорт об ошибке.

Так вот я наглухо забыл как это делается. Может кто подсказать, или ссылку на такой материал подкинуть.

Cupper
()

Перегрузка вирт функции в шаблоне

Подскажите почему это не компилируется

#include <iostream>
using namespace std;

class Logger
{
public:

    int logger()
    { return 5; }

    virtual void logger(int)
    { ; }

    virtual ~Logger(){}
};

template <typename T>
class Base: public Logger
{
public:
    virtual void logger(int)
    { ; }

    virtual ~Base(){}
};

class Derived: public Base<int>
{
public:
    void f()
    {
        logger(logger());
    }
};

int main() {

    Derived d;
    d.f();
}
../src/overload_fin_template.cpp:40:23: ошибка: нет подходящей функции для вызова «Derived::logger()»
../src/overload_fin_template.cpp:40:23: замечание: candidate is:
../src/overload_fin_template.cpp:29:18: замечание: void Base<T>::logger(int) [with T = int]
../src/overload_fin_template.cpp:29:18: замечание:   candidate expects 1 argument, 0 provided
make: *** [src/overload_fin_template.o] Ошибка 1

Если в Base убрать перезрузку метода virtual void logger(int) то все как бы работает (собстно как и ожидалось).

Выжно, что

    int logger()
    { return 5; }

    virtual void logger(int)
    { ; }
имееют одинаковое имя, если сделать разные то компилируется.

Cupper
()

загрузка динамической библиотеки дважды

Если я например сделаю дважды dl_open на одной и тойже библиотеке, она же от этого второй раз не загрузиться. Т.е. если у меня например есть глобальные, статические переменные в библиотеке, то все они будут в единственном числе, не важно сколько раз я бы не загружал библиотеку?

Cupper
()

boost::log channel vs attribute

Ни как не могу понять в чем принципиальная разница между channel и attibute в boost log (1.54+). Вроде как и тот и другой просто ставит метку к записи, по которой потом можно фильтровать, причем фильтрация выглядит абсолютно одинакого.

По тестам производительности, source + channel на наносекунды обгоняет source + attribute, так что тут не принципиально logger(channel), разница в 50 миллисекунд на 500000 записей.

 ,

Cupper
()

Ubuntu 13.10 умирает

Стоит у меня Ubuntu 13.10 со всеми апдейтами и она умирает. Разваливается на глазах, постоянно репроты с ошибками, skype на видио связи постоянно дохнет.

Так случилось, что вместе с 13.10 я себе SSD поставил, и теперь не понимаю то ли он так хреного работает толи 13.10 полный отстой.

 

Cupper
()

Thread safe queue и сбор статистики о времение

Есть у меня код который обеспечивает асинхронное выполнение тасков.

Стандартный случай, потоко безопасная очередь, одни в нее кладут, другие берут от туда и выполняют функтор.

Есть пару ухищрений, типа дедлайнов и cancel_hook в случае если таска просрочилась. Ну т.е. кладя задачу в очередь у нее либо вызовется метод execute() либо cancel().

Нужно мне добавить возможность сбора следующей статистики. 1. Сколько задача устанавливалась в очередь (при установки в очередь как минимум нужно схватить мютекс, как максимум есть capacity и ожидания в случае если они досиг лимита) 2. Сколько по времение задача провела в очедеи то тех поо пока ее от туда не вытащили. 3. сколько выполнялась 4. все это усредненное

Как сделано сейчас: статистика хранится в самом объекте который ставится в очередь и далее везде где нужно ее замерять, она устанавливается в сам объект. И в конце из объекта она куда то там сохраняется (т.е. объект нужно еще параметризировать тем куда ее сохранять).

схематично это выглядит так: push:

  • Засеч время при входе в метод
  • захватить мютекс
  • поставить задачу в очередь
  • засеч время выхода из метода
  • отпустить мютекс

pop:

  • Захватить мютекс
  • получить задачу из очереди
  • засем время начала выполнения
  • выполнение задачи
  • зачем время завершения
  • сохранить статистику в X

Мне не нравиться, что эту статистику приходится хранить в объектe. Поидее пользователю на нее вообще насрать. Хужее, что ее надо не просто получать, ее нужно хранить и аккамулировать, т.е. мы должны напрягать пользователя тем, что бы он подумал об этом. Мне кажется логичным что эта статистика должна накапливаться в самой очереди без участия пользователя. Но так как нужно знать когда объект был пушнут и когда был попнут, эту статистику как то нужно связать с самим объектом.

Хранить что то типо отдельного маппинга это вообще не решение. Притом сбор этоq статистики происходит на разных уровнях. Если немного подумать, то видно что информацию о пуше мы может собирать только под мютексом. А статистику о выполнении задачи нужно уже собирать на уровне выше. А еще cancel() выполняется опять на другом уровне. Единственно что объединяет все эти уровни это только объект (пользовательский тип).

А теперь добавляем что все это шаблонное, и все уровни пронизаци одним шаблонным типом (который указаль пользователь). А напрягать пользователя тем, что бы его шаблонный тип отвечал нашему специальному интерфейсу для сбора статистики нехочется. Даже если все это мы сделаем за него а ему нужно просто унаследоватся.

Может кто делал такое? Посоветуйте?

Cupper
()

boost::multi_index_container<const int>

Кто знает почему субж не умеет работать с константными типами?

#include <iostream>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/global_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>

int main()
{
	boost::multi_index_container<const int> t;

	t.insert(5);
	std::cout << *t.begin() << std::endl;
}
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp"
In file included from /usr/include/x86_64-linux-gnu/c++/4.7/./bits/c++allocator.h:34:0,
                 from /usr/include/c++/4.7/bits/allocator.h:48,
                 from /usr/include/c++/4.7/string:43,
                 from /usr/include/c++/4.7/bits/locale_classes.h:42,
                 from /usr/include/c++/4.7/bits/ios_base.h:43,
                 from /usr/include/c++/4.7/ios:43,
                 from /usr/include/c++/4.7/ostream:40,
                 from /usr/include/c++/4.7/iostream:40,
                 from ../main.cpp:13:
/usr/include/c++/4.7/ext/new_allocator.h: In instantiation of «class __gnu_cxx::new_allocator<const int>»:
/usr/include/c++/4.7/bits/allocator.h:89:11:   required from «class std::allocator<const int>»
/usr/include/boost/detail/allocator_utilities.hpp:149:31:   required from «struct boost::detail::allocator::rebinder<std::allocator<const int> >::result<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > > >»
/usr/include/boost/detail/allocator_utilities.hpp:158:49:   required from «struct boost::detail::allocator::compliant_allocator_rebind_to<std::allocator<const int>, boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > > >»
/usr/include/boost/mpl/eval_if.hpp:60:31:   required from «struct boost::mpl::eval_if_c<false, boost::detail::allocator::partial_std_allocator_rebind_to<std::allocator<const int>, boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > > >, boost::detail::allocator::compliant_allocator_rebind_to<std::allocator<const int>, boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > > > >»
/usr/include/boost/detail/allocator_utilities.hpp:164:8:   required from «struct boost::detail::allocator::rebind_to<std::allocator<const int>, boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > > >»
/usr/include/boost/multi_index_container.hpp:70:7:   required from «class boost::multi_index::multi_index_container<const int>»
../main.cpp:22:42:   required from here
/usr/include/c++/4.7/ext/new_allocator.h:83:7: ошибка: «const _Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::const_reference) const [with _Tp = const int; __gnu_cxx::new_allocator<_Tp>::const_pointer = const int*; __gnu_cxx::new_allocator<_Tp>::const_reference = const int&]» cannot be overloaded
/usr/include/c++/4.7/ext/new_allocator.h:79:7: ошибка: with «_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = const int; __gnu_cxx::new_allocator<_Tp>::pointer = const int*; __gnu_cxx::new_allocator<_Tp>::reference = const int&]»
In file included from /usr/include/boost/multi_index/detail/base_type.hpp:21:0,
                 from /usr/include/boost/multi_index_container.hpp:33,
                 from ../main.cpp:15:
/usr/include/boost/multi_index/detail/index_base.hpp: In instantiation of «boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::node_type* boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::insert_(boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::value_param_type, boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::node_type*) [with Value = const int; IndexSpecifierList = boost::multi_index::indexed_by<boost::multi_index::ordered_unique<boost::multi_index::identity<const int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>; Allocator = std::allocator<const int>; boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::node_type = boost::multi_index::detail::index_node_base<const int, std::allocator<const int> >; boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::value_param_type = const int]»:
/usr/include/boost/multi_index/ordered_index.hpp:633:63:   required from «boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::node_type* boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::insert_(boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::value_param_type, boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::node_type*) [with KeyFromValue = boost::multi_index::identity<const int>; Compare = std::less<const int>; SuperMeta = boost::multi_index::detail::nth_layer<1, const int, boost::multi_index::indexed_by<boost::multi_index::ordered_unique<boost::multi_index::identity<const int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, std::allocator<const int> >; TagList = boost::mpl::vector0<mpl_::na>; Category = boost::multi_index::detail::ordered_unique_tag; boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::node_type = boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > >; typename SuperMeta::type::node_type = boost::multi_index::detail::index_node_base<const int, std::allocator<const int> >; boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::value_param_type = const int]»
/usr/include/boost/multi_index_container.hpp:488:40:   required from «std::pair<typename boost::multi_index::detail::multi_index_base_type<Value, IndexSpecifierList, Allocator>::type::node_type*, bool> boost::multi_index::multi_index_container<Value, IndexSpecifierList, Allocator>::insert_(const Value&) [with Value = const int; IndexSpecifierList = boost::multi_index::indexed_by<boost::multi_index::ordered_unique<boost::multi_index::identity<const int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>; Allocator = std::allocator<const int>; typename boost::multi_index::detail::multi_index_base_type<Value, IndexSpecifierList, Allocator>::type::node_type = boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > >]»
/usr/include/boost/multi_index/detail/index_base.hpp:150:30:   required from «std::pair<typename boost::multi_index::detail::multi_index_node_type<Value, IndexSpecifierList, Allocator>::type*, bool> boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::final_insert_(boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::value_param_type) [with Value = const int; IndexSpecifierList = boost::multi_index::indexed_by<boost::multi_index::ordered_unique<boost::multi_index::identity<const int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>; Allocator = std::allocator<const int>; typename boost::multi_index::detail::multi_index_node_type<Value, IndexSpecifierList, Allocator>::type = boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<const int, std::allocator<const int> > >; boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::value_param_type = const int]»
/usr/include/boost/multi_index/ordered_index.hpp:275:61:   required from «std::pair<boost::multi_index::detail::bidir_node_iterator<boost::multi_index::detail::ordered_index_node<typename SuperMeta::type::node_type> >, bool> boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::insert(boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::value_param_type) [with KeyFromValue = boost::multi_index::identity<const int>; Compare = std::less<const int>; SuperMeta = boost::multi_index::detail::nth_layer<1, const int, boost::multi_index::indexed_by<boost::multi_index::ordered_unique<boost::multi_index::identity<const int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, std::allocator<const int> >; TagList = boost::mpl::vector0<mpl_::na>; Category = boost::multi_index::detail::ordered_unique_tag; typename SuperMeta::type::node_type = boost::multi_index::detail::index_node_base<const int, std::allocator<const int> >; boost::multi_index::detail::ordered_index<KeyFromValue, Compare, SuperMeta, TagList, Category>::value_param_type = const int]»
../main.cpp:24:12:   required from here
/usr/include/boost/multi_index/detail/index_base.hpp:88:5: ошибка: нет соответствующей функции для вызова «construct(boost::multi_index::detail::index_node_base<const int, std::allocator<const int> >::value_type*, boost::multi_index::detail::index_base<const int, boost::multi_index::indexed_by<boost::multi_index::ordered_unique<boost::multi_index::identity<const int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, std::allocator<const int> >::value_param_type&)»
/usr/include/boost/multi_index/detail/index_base.hpp:88:5: замечание: candidate is:
In file included from /usr/include/boost/multi_index_container.hpp:20:0,
                 from ../main.cpp:15:
/usr/include/boost/detail/allocator_utilities.hpp:176:6: замечание: template<class Type> void boost::detail::allocator::construct(void*, const Type&)
/usr/include/boost/detail/allocator_utilities.hpp:176:6: замечание:   template argument deduction/substitution failed:
In file included from /usr/include/boost/multi_index/detail/base_type.hpp:21:0,
                 from /usr/include/boost/multi_index_container.hpp:33,
                 from ../main.cpp:15:
/usr/include/boost/multi_index/detail/index_base.hpp:88:5: замечание:   cannot convert «& x->boost::multi_index::detail::index_node_base<Value, Allocator>::value<const int, std::allocator<const int> >()» (type «boost::multi_index::detail::index_node_base<const int, std::allocator<const int> >::value_type* {aka const int*}») to type «void*»
make: *** [main.o] Ошибка 1

Такое чувство, что я единственнй кто это пробовал, ибо в гугле ничего похожего ненашел.

Cupper
()

Thread safe Queue + delete object's with O(1)

Нужно реализовать вот такую незамысловатую штуку. Обычная thread safe очередь но с возможность удаления поставленных в нее объектов.

При этом хотелось бы что бы «опцию» удаления объектов из очереди можно было бы отключить безболезненно если она не нужна.

Реализация сводится к тому что бы в очереди хранить не сам объкт, а некий подставной хендл. Соотвественно при добавлении в очередь очередного объекта возвращать на него хендел через который его можно удалить.

Если пораскинуть мозгами, то появляются вот такие требования к реализации:

  • Сторона которая делает push получает хендел через который можно удалить объект
  • Если кто то сделал pop этого объекта, то удалить его через хендл полученных из push уже нельзя
  • Если объект был удален, то pop возвращает пустой хендл, поэтому перед использованием объекта полученного из pop нужно его проверить (хотя эту проверку можно делать сразу в pop)

У меня получилась вот такая реализация:

template<class T, class H = ::Holder<T> >
class Queue
{
	typedef typename H::Ptr Ptr;

public:
	typedef H Holder;

	object():stop_(false){}

	Holder push(T* t)
	{
		std::unique_lock<std::mutex> lock(mtx_);
		Holder holder(t);
		q_.push_back(holder.ptr());
		cond_.notify_one();
		return holder;
	}
	Holder pop()
	{
		std::unique_lock<std::mutex> lock(mtx_);
		while(q_.empty() && !stop_) cond_.wait(lock);
		if(stop_ && q_.empty())
			throw std::runtime_error("stopped");
		Ptr ptr = q_.front();
		q_.pop_front();
		return Holder(ptr);
	}

	void stop()
	{
		std::unique_lock<std::mutex> lock(mtx_);
		stop_ = true;
		cond_.notify_one();
	}
private:
	std::deque<Ptr> q_;
	bool stop_;
	std::mutex mtx_;
	std::condition_variable cond_;
};
Сразу бросается в глаза, что очередь может работать только с указателями. Но, в противном случае, как бы мы могли удалить объект в очереди (ниже будет понятнее).

Первый тип хендлера объекта, просто замещает обычный указатель. Нужен из за поддержки единиго кода в самой очереди

template<class T>
class Holder
{
public:
	typedef T* Ptr;

public:
	Holder(T* t): t_(t){}

	void reset() {  }

	operator bool(){ return static_cast<bool>(t_); }
	T* operator->() {return t_;}
	Ptr ptr() { return t_; }

private:
	T* t_;
};

Второй тип хендлера, подразумевает что настоящим владельцем (хранителем объекта) будет сам pusher

template<class T>
class RemovableHolder
{
public:
	typedef std::weak_ptr<T> Ptr;

public:
	RemovableHolder(T* t):t_(t){}
	RemovableHolder(const Ptr& ptr):t_(ptr.lock()){}

	void reset() { t_.reset(); }

	operator bool(){ return static_cast<bool>(t_); }
	T* operator->() {return t_.get();}
	Ptr ptr() { return std::weak_ptr<T>(t_); }

private:
	std::shared_ptr<T> t_;
};
Проще говоря в самой очереди мы храним лишь weak_ptr, первый shared_ptr мы отдаем push'ру и он собственно может в любой момент удалить реальный объект. После операции pop у нас появляется еще один шаред, и тем самым мы добиваемся требуемого. Но тут есть одна неприятность. Pusher должен хранить все объекты. Это не очень удобно, вернее это вообще не удобно.

Третий холдер, решает эту проблему

template<class T>
class ExRemovableHolder
{
	struct Impl
	{
	public:
		Impl(T* t):t_(t), is_popped_(false){}
		void destroy(bool from_popper)
		{
			std::unique_lock<std::mutex> lock(mtx_);
			if(is_popped_ && !from_popper)
			{
				return;
			}
			if(t_)
			{
				delete t_;
				t_ = 0;
			}
		}
		~Impl()
		{
			delete t_;
		}

	public:
		std::mutex mtx_;
		T* t_;
		bool is_popped_;
	};

public:
	typedef std::shared_ptr<Impl> Ptr;

public:
	ExRemovableHolder(T* t):impl_(new Impl(t)), popper_(false){}
	ExRemovableHolder(Ptr& ptr):popper_(true)
	{
		std::unique_lock<std::mutex> lock(ptr->mtx_);
		if(ptr->t_)
		{
			impl_ = ptr;
			impl_->is_popped_ = true;
		}
	}

	void reset() { impl_->destroy(popper_); }

	operator bool(){ return static_cast<bool>(impl_); }
	T* operator->() {return impl_->t_;}
	Ptr ptr() { return impl_; }

private:
	std::shared_ptr<Impl> impl_;
	bool popper_;
};
Теперь у нас pusher,popper и в самой очереди хранится shared_ptr. Pusher может его в ручном порядке удалить. Притом только если этот объект еще не был pop'нут. Так же нам в принципе нет необходимости вообще хранить объекты из pushra. Так же объект может быть удален в ручную из pop'ra. И так же объект будет удален автоматически если его вообще никто не удалял.

Вот пример как это используется

typedef Queue<Person, ExRemovableHolder<Person> > TSQueue;
typedef simple_object<TSQueue::Holder> DestroyQueue;

void popper(TSQueue& q)
{
	try
	{
		while(true)
		{
			TSQueue::Holder tmp = q.pop();
			if(tmp)
			{
				tmp->name();
				tmp.reset();
			}
		}
	}
	catch(...)
	{
		std::cout << "popper finished\n";
	}
}
void destroyer(DestroyQueue& q)
{
	try
	{
		while(true)
		{
			TSQueue::Holder tmp = q.pop();
			tmp.reset();
		}
	}
	catch(...)
	{
		std::cout << "destroyer finished\n";
	}
}

int main()
{
	TSQueue q;
	std::thread th(popper, std::ref(q));

	DestroyQueue d;
	std::thread thd(destroyer, std::ref(d));

	const int repeat = 9999999;
	for(int i=1; i<=repeat; i++)
	{
		TSQueue::Holder h = q.push(new Person("Vasya"));
		d.push(h);
	}

	q.stop();
	d.stop();
	th.join();
	thd.join();
}

Зачем вся эта котовасия понадобилась. Это вроде как ActiveObject где активные объекты должны исполнятся в пуле тредов. Т.е. очередь это интерфейс для асинхронного выполнения задач. Притом логично, что после постановки задачи в очередь, может произойти так, что эта задача станет уже не актуальной до момента, когда до нее дойдет очередь выполнения (например клиент отключился), и тогда ее выполнения будет бессмысленным.

Если система слобосвязана, то это по сути единственнй способ отменить выполнения таски.

А теперь я хотел бы выслушать вашу критику. И в плане идеи и в плане реализации.

 

Cupper
()

RSS подписка на новые темы