Vous êtes sur la page 1sur 27

Boost en 5 minutos

Boost.MultiIndex en 40

using std::cpp 2013


Joaqun M Lpez Muoz <joaquin@tid.es>
Telefnica Digital
Video Products
Definition & Strategy
Madrid,
noviembre
2013

Las libreras Boost

Las libreras Boost

Libreras open source de propsito general que complementan e


interaccionan con la librera estndar de C++

En torno a 120 libreras independientes (Boost 1.55)

namespace boost

La mayora header-only

Buen soporte de MSVC, GCC, Clang

10 de ellas incluidas en C++11 (con sutiles cambios)

Categoras

Algoritmos

Concurrencia

Contenedores

Computacin numrica

Estructuras de datos

Matemticas

Metaprogramacin

Programacin de sistemas

Programacin funcional

Procesamiento de texto

Las joyas de la corona

Las joyas de la corona

Boost.Asio

Networking, sockets, DNS

Boost.Bind

Currificacin de funciones

Boost.Filesystem

Paths, ficheros, directorios

Boost.Function

Type erasure para objetos llamables

Boost.Graph

Estructuras y algoritmos genricos sobre grafos

Boost.Interprocess

Memoria compartida, mutexes entre procesos

Boost.Random

Generadores y distribuciones

Boost.Regex

Expresiones regulares

Boost.SmartPtr

shared_ptr, scoped_ptr

Boost.Thread

Multithreading portable

Las joyas de la corona

Boost.Asio

Boost.Bind

Boost.Filesystem

Boost.Function

Boost.Graph

Boost.Interprocess

Boost.Random

Boost.Regex

Boost.SmartPtr

Boost.Thread

Las joyas de la corona

Boost.Asio

Boost.Bind

Boost.Filesystem

Boost.Function

Boost.Graph

Boost.Interprocess

Boost.Random

Boost.Regex

Boost.SmartPtr

Boost.Thread

Boost.MultiIndex

Boost.MultiIndex

Contenedores con mltiples interfaces de acceso a los elementos

Disponible desde Boost 1.32 (noviembre 2004)

Dbilmente inspirada en conceptos de bases de datos relacionales

Contenedor multindice

tabla relacional

Interfaz de acceso

ndice

Soporte de acceso secuencial, ordenado, claves compuestas

Header-only

Uso intensivo de metaprogramacin basada en templates

Algunos usuarios distinguidos

Software del experimento ATLAS del CERN

Librera Folly de Facebook

DNS Server BIND 10 del Internet Systems Consortium

El typedef ms largo de la historia?


typedef multi_index_container<
boost::shared_ptr< Host >,
indexed_by<
hashed_unique< const_mem_fun<Host,int,&Host::getID> >, // 0 - ID index
ordered_non_unique< tag<age>,const_mem_fun<Host,int,&Host::getAgeInY> >, // 1 - Age index
hashed_non_unique< tag<household>,const_mem_fun<Host,int,&Host::getHousehold> >, // 2 - Household index
ordered_non_unique< // 3 - Eligible by age & household
tag<aeh>,
composite_key<
Host,
const_mem_fun<Host,int,&Host::getAgeInY>,
const_mem_fun<Host,bool,&Host::isEligible>,
const_mem_fun<Host,int,&Host::getHousehold>
>
>,
ordered_non_unique< // 4 - Eligible by household (all single adults)
tag<eh>,
composite_key<
Host,
const_mem_fun<Host,bool,&Host::isEligible>,
const_mem_fun<Host,int,&Host::getHousehold>
>
>,
ordered_non_unique< // 5 - Neighborhood & age
tag<an>,
composite_key<
Host,
const_mem_fun<Host,int,&Host::getNeighborhood>,
const_mem_fun<Host,int,&Host::getAgeInY>
>
>,
ordered_non_unique< // 6 - Household & age
tag<ah>,
composite_key<
Host,
const_mem_fun<Host,int,&Host::getHousehold>,
const_mem_fun<Host,int,&Host::getAgeInY>
>
>,
ordered_non_unique< tag<inf>,const_mem_fun<Host,bool,&Host::isInfected> > // 7 - Carriage status
> // end indexed_by
> HostContainer;

Lenguajes embebidos especficos de dominio (DSEL)

Lenguajes embebidos especficos de dominio (DSEL)

Lenguajes dentro de otro lenguaje

Busca domain specific embedded language en Google

Ejemplos

Frmulas matemticas y lgicas

Notacin de ajedrez

Estequiometra

Expresiones regulares

1. e4 c5 2. Nf3 d6 3. Bb5+ Bd7 4. Bxd7+ Qxd7 5. c4 Nc6


6. Nc3 Nf6 7. 0-0 g6 8. d4 cxd4 9. Nxd4 Bg7 10. Nde2 Qe6!?

CH4 + 2O2 CO2 + 2H2O


static const boost::regex e("(\\d{4}[-]){3}\\d{4}");

El objetivo de un DSEL es expresar fiel y concisamente las ideas del dominio


en el lenguaje padre

Volveremos al typedef anterior ms tarde

Bienvenido a la universidad
struct employee
{
int
id;
std::string name;
int
department_id;
unsigned int salary;
};
bool operator<(const employee& x,const employee& y){return x.id<y.id;}
typedef std::set<employee> payroll;
enum {logic=0,physics=1,philosophy=2};
int main()
{
payroll p{
{0,"Goedel Kurt",logic,20000},
{1,"Russell Bernie",philosophy,25000},
{2,"Frege Gottlob",logic,18000},
{3,"Einstein Al",physics,21000},
{4,"Church Alonzo",logic,25000}
};
}

Algunas tareas sencillas?

Lista los profesores en orden alfabtico

void list_by_name(const payroll& p)


{
std::vector<employee> v(p.begin(),p.end());
std::sort(
v.begin(),v.end(),
[](const employee& x,const employee& y){return x.name<y.name;});
for(const auto& x:v)std::cout<<x<<std::endl;
}

Cerramos el departamento de filosofa

void suppress_department(payroll& p,int department_id)


{
for(auto it=p.begin();it!=p.end();){
if(it->department_id==department_id)it=p.erase(it);
else ++it;
}
}

Estas implementaciones son tremendamente ineficientes!

(Y no deberamos cerrar filosofa)

Diferentes rdenes para diferentes tareas

Goedel Kurt

Russell Bernie

Frege Gottlob

Einstein Al

Church Alonzo

logic

philosophy

logic

physics

logic

20000

25000

18000

21000

25000

Church Alonzo

Einstein Al

Frege Gottlob

Goedel Kurt

Russell Bernie

logic

physics

logic

logic

philosophy

25000

21000

18000

20000

25000

Goedel Kurt

Frege Gottlob

Church Alonzo

Einstein Al

Russell Bernie

logic

logic

logic

physics

philosophy

20000

18000

25000

21000

25000

Mejoremos la eficiencia

Solucin pedestre #1

typedef std::set<employee>
payroll;
typedef std::set<employee,less_by_name>
payroll_by_name;
typedef std::multiset<employee,less_by_department_id> payroll_by_department_id;

Solucin pedestre #2

typedef std::set<employee>
payroll;
typedef std::set<const employee*,less_by_name>
payroll_by_name;
typedef std::multiset<const employee*,less_by_department_id> payroll_by_department_id;

La implementacin se deja al lector como ejercicio

Define less_by_name, less_by_department_id

Sincroniza inserciones y borrados

Ojo con las excepciones!

insert({0,"Goedel Kurt",logic,20000});
insert({5,"Goedel Kurt",physics,18000});

Buena suerte!

Boost.MultiIndex al rescate
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
using namespace boost::multi_index;
typedef multi_index_container<
employee,
indexed_by<
ordered_unique<
member<employee,int,&employee::id>>,
ordered_unique<
member<employee,std::string,&employee::name>>,
ordered_non_unique< member<employee,int,&employee::department_id>>
>
> payroll;

Con tags

struct by_id{}; struct by_name{}; struct by_dep_id{};


typedef multi_index_container<
employee,
indexed_by<
ordered_unique<
tag<by_id>,
member<employee,int,&employee::id>>,
ordered_unique<
tag<by_name>, member<employee,std::string,&employee::name>>,
ordered_non_unique< tag<by_dep_id>,member<employee,int,&employee::department_id>>
>
> payroll;

Lo peor ya ha pasado
int main()
{
payroll p{
{0,"Goedel Kurt",logic,20000},
{1,"Russell Bernie",philosophy,25000},
{2,"Frege Gottlob",logic,18000},
{3,"Einstein Al",physics,21000},
{4,"Church Alonzo",logic,25000}
};
p.insert({5,"Goedel Kurt",physics,18000}); // fails, Kurt is already in
}
void list_by_name(const payroll& p)
{
for(const auto& x:p.get<by_name>())std::cout<<x<<std::endl;
}
void suppress_department(payroll& p,int department_id)
{
p.get<by_dep_id>().erase(department_id);
}

Extractores de clave

Provistos directamente por Boost.MultiIndex


#include <boost/multi_index/identity.hpp>
identity<element>

struct element
{
int

value;

std::string id()const;

#include <boost/multi_index/member.hpp>
member<element,int,&element::value>

#include <boost/multi_index/mem_fun.hpp>
const_mem_fun<element,std::string,&element::id>

};
double property(const element& x);

#include <boost/multi_index/global_fun.hpp>
global_fun<const element&,double,property>
#include <boost/multi_index/composite_key.hpp>
composite_key<
element,
member<element,int,&element::value>,
const_mem_fun<element,std::string,&element::id>
>

En casos muy especiales, el usuario puede definir sus propios extractores de


clave

Tipos de ndices

Ordenados (como std::set/std::multiset)

#include <boost/multi_index/ordered_index.hpp>
ordered_unique
<tag,key extractor,comparison predicate>
ordered_non_unique<tag,key extractor,comparison predicate>

Hashed (como std::unordered_set/std::unordered_multiset)

#include <boost/multi_index/hashed_index.hpp>
hashed_unique
<tag,key extractor,hash function,equality predicate>
hashed_non_unique<tag,key extractor,hash function,equality predicate>

Secuenciales (como std::list)

#include <boost/multi_index/sequenced_index.hpp>
sequenced<tag>

Acceso aleatorio (ms o menos como std::vector)

#include <boost/multi_index/random_access_index.hpp>
random_access<tag>

Esto ya no suena a chino (o s?)


typedef multi_index_container<
boost::shared_ptr< Host >,
indexed_by<
hashed_unique< const_mem_fun<Host,int,&Host::getID> >, // 0 - ID index
ordered_non_unique< tag<age>,const_mem_fun<Host,int,&Host::getAgeInY> >, // 1 - Age index
hashed_non_unique< tag<household>,const_mem_fun<Host,int,&Host::getHousehold> >, // 2 - Household index
ordered_non_unique< // 3 - Eligible by age & household
tag<aeh>,
composite_key<
Host,
const_mem_fun<Host,int,&Host::getAgeInY>,
const_mem_fun<Host,bool,&Host::isEligible>,
const_mem_fun<Host,int,&Host::getHousehold>
>
>,
ordered_non_unique< // 4 - Eligible by household (all single adults)
tag<eh>,
composite_key<
Host,
const_mem_fun<Host,bool,&Host::isEligible>,
const_mem_fun<Host,int,&Host::getHousehold>
>
>,
ordered_non_unique< // 5 - Neighborhood & age
tag<an>,
composite_key<
Host,
const_mem_fun<Host,int,&Host::getNeighborhood>,
const_mem_fun<Host,int,&Host::getAgeInY>
>
>,
ordered_non_unique< // 6 - Household & age
tag<ah>,
composite_key<
Host,
const_mem_fun<Host,int,&Host::getHousehold>,
const_mem_fun<Host,int,&Host::getAgeInY>
>
>,
ordered_non_unique< tag<inf>,const_mem_fun<Host,bool,&Host::isInfected> > // 7 - Carriage status
> // end indexed_by
> HostContainer;

Un ltimo ejemplo: una lista MRU en 36 lneas


template <typename Item>
class mru_list
{
typedef multi_index_container<
Item,
indexed_by<
sequenced<>,
hashed_unique<identity<Item> >
>
> item_list;
public:
typedef Item
item_type;
typedef typename item_list::iterator iterator;
mru_list(std::size_t max_num_items_):max_num_items(max_num_items_){}
void insert(const item_type& item)
{
std::pair<iterator,bool> p=il.push_front(item);
if(!p.second){
// duplicate item
il.relocate(il.begin(),p.first); // put in front
}
else if(il.size()>max_num_items){ // keep the length <= max_num_items
il.pop_back();
}
}
iterator begin(){return il.begin();}
iterator end(){return il.end();}
private:
item_list
il;
std::size_t max_num_items;
};

Slo ha habido tiempo para explorar la superficie

Slo ha habido tiempo para explorar la superficie

Modificacin de elementos

Llaves compuestas

Llaves heterogneas

Contenedores de punteros

Serializacin

Boost.MultiIndex y Boost.Interprocess

Si quieres seguir investigando

Si quieres seguir investigando

Boost

boost.org

Boost.MultiIndex

boost.org/libs/multi_index

Listas de correo de Boost

Usuarios

lists.boost.org/boost-users

Desarrolladores

lists.boost.org/Archives/boost

Otros recursos sobre C++

Standard C++ web

isocpp.org

reddit CPP

reddit.com/r/cpp

Channel 9

channel9.msdn.com/tags/c++

Stack Overflow

stackoverflow.com

Compiladores online con soporte de Boost

Coliru

stacked-crooked.com

Boost en 5 minutos
Boost.MultiIndex en 40

Gracias

using std::cpp 2013


Joaqun M Lpez Muoz <joaquin@tid.es>
Madrid, noviembre 2013

Vous aimerez peut-être aussi