bd8ea1bc86
[SVN r47045]
294 lines
7.7 KiB
C++
294 lines
7.7 KiB
C++
/* Boost.MultiIndex example of use of Boost.Interprocess allocators.
|
|
*
|
|
* Copyright 2003-2008 Joaquin M Lopez Munoz.
|
|
* Distributed under the Boost Software License, Version 1.0.
|
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
|
* http://www.boost.org/LICENSE_1_0.txt)
|
|
*
|
|
* See http://www.boost.org/libs/multi_index for library home page.
|
|
*/
|
|
|
|
#if !defined(NDEBUG)
|
|
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
|
|
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
|
|
#endif
|
|
|
|
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
|
#include <algorithm>
|
|
#include <boost/interprocess/allocators/allocator.hpp>
|
|
#include <boost/interprocess/containers/string.hpp>
|
|
#include <boost/interprocess/managed_mapped_file.hpp>
|
|
#include <boost/interprocess/sync/named_mutex.hpp>
|
|
#include <boost/interprocess/sync/scoped_lock.hpp>
|
|
#include <boost/multi_index_container.hpp>
|
|
#include <boost/multi_index/ordered_index.hpp>
|
|
#include <boost/multi_index/member.hpp>
|
|
#include <iostream>
|
|
#include <iterator>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
using boost::multi_index_container;
|
|
using namespace boost::multi_index;
|
|
namespace bip=boost::interprocess;
|
|
|
|
/* shared_string is a string type placeable in shared memory,
|
|
* courtesy of Boost.Interprocess.
|
|
*/
|
|
|
|
typedef bip::basic_string<
|
|
char,std::char_traits<char>,
|
|
bip::allocator<char,bip::managed_mapped_file::segment_manager>
|
|
> shared_string;
|
|
|
|
/* Book record. All its members can be placed in shared memory,
|
|
* hence the structure itself can too.
|
|
*/
|
|
|
|
struct book
|
|
{
|
|
shared_string name;
|
|
shared_string author;
|
|
unsigned pages;
|
|
unsigned prize;
|
|
|
|
book(const shared_string::allocator_type& al):
|
|
name(al),author(al),pages(0),prize(0)
|
|
{}
|
|
|
|
friend std::ostream& operator<<(std::ostream& os,const book& b)
|
|
{
|
|
os<<b.author<<": \""<<b.name<<"\", $"<<b.prize<<", "<<b.pages<<" pages\n";
|
|
return os;
|
|
}
|
|
};
|
|
|
|
/* partial_str_less allows for partial searches taking into account
|
|
* only the first n chars of the strings compared against. See
|
|
* Tutorial: Basics: Special lookup operations for more info on this
|
|
* type of comparison functors.
|
|
*/
|
|
|
|
/* partial_string is a mere string holder used to differentiate from
|
|
* a plain string.
|
|
*/
|
|
|
|
struct partial_string
|
|
{
|
|
partial_string(const shared_string& str):str(str){}
|
|
shared_string str;
|
|
};
|
|
|
|
struct partial_str_less
|
|
{
|
|
bool operator()(const shared_string& x,const shared_string& y)const
|
|
{
|
|
return x<y;
|
|
}
|
|
|
|
bool operator()(const shared_string& x,const partial_string& y)const
|
|
{
|
|
return x.substr(0,y.str.size())<y.str;
|
|
}
|
|
|
|
bool operator()(const partial_string& x,const shared_string& y)const
|
|
{
|
|
return x.str<y.substr(0,x.str.size());
|
|
}
|
|
};
|
|
|
|
/* Define a multi_index_container of book records with indices on
|
|
* author, name and prize. The index on names allows for partial
|
|
* searches. This container can be placed in shared memory because:
|
|
* * book can be placed in shared memory.
|
|
* * We are using a Boost.Interprocess specific allocator.
|
|
*/
|
|
|
|
/* see Compiler specifics: Use of member_offset for info on
|
|
* BOOST_MULTI_INDEX_MEMBER
|
|
*/
|
|
|
|
typedef multi_index_container<
|
|
book,
|
|
indexed_by<
|
|
ordered_non_unique<
|
|
BOOST_MULTI_INDEX_MEMBER(book,shared_string,author)
|
|
>,
|
|
ordered_non_unique<
|
|
BOOST_MULTI_INDEX_MEMBER(book,shared_string,name),
|
|
partial_str_less
|
|
>,
|
|
ordered_non_unique<
|
|
BOOST_MULTI_INDEX_MEMBER(book,unsigned,prize)
|
|
>
|
|
>,
|
|
bip::allocator<book,bip::managed_mapped_file::segment_manager>
|
|
> book_container;
|
|
|
|
/* A small utility to get data entered via std::cin */
|
|
|
|
template<typename T>
|
|
void enter(const char* msg,T& t)
|
|
{
|
|
std::cout<<msg;
|
|
std::string str;
|
|
std::getline(std::cin,str);
|
|
std::istringstream iss(str);
|
|
iss>>t;
|
|
}
|
|
|
|
void enter(const char* msg,std::string& str)
|
|
{
|
|
std::cout<<msg;
|
|
std::getline(std::cin,str);
|
|
}
|
|
|
|
void enter(const char* msg,shared_string& str)
|
|
{
|
|
std::cout<<msg;
|
|
std::string stdstr;
|
|
std::getline(std::cin,stdstr);
|
|
str=stdstr.c_str();
|
|
}
|
|
|
|
int main()
|
|
{
|
|
/* Create (or open) the memory mapped file where the book container
|
|
* is stored, along with a mutex for synchronized access.
|
|
*/
|
|
|
|
bip::managed_mapped_file seg(
|
|
bip::open_or_create,"./book_container.db",
|
|
65536);
|
|
bip::named_mutex mutex(
|
|
bip::open_or_create,"7FD6D7E8-320B-11DC-82CF-F0B655D89593");
|
|
|
|
/* create or open the book container in shared memory */
|
|
|
|
book_container* pbc=seg.find_or_construct<book_container>("book container")(
|
|
book_container::ctor_args_list(),
|
|
book_container::allocator_type(seg.get_segment_manager()));
|
|
|
|
std::string command_info=
|
|
"1. list books by author\n"
|
|
"2. list all books by prize\n"
|
|
"3. insert a book\n"
|
|
"4. delete a book\n"
|
|
"0. exit\n";
|
|
|
|
std::cout<<command_info;
|
|
|
|
/* main loop */
|
|
|
|
for(bool exit=false;!exit;){
|
|
int command=-1;
|
|
enter("command: ",command);
|
|
|
|
switch(command){
|
|
case 0:{ /* exit */
|
|
exit=true;
|
|
break;
|
|
}
|
|
case 1:{ /* list books by author */
|
|
std::string author;
|
|
enter("author (empty=all authors): ",author);
|
|
|
|
/* operations with the container must be mutex protected */
|
|
|
|
bip::scoped_lock<bip::named_mutex> lock(mutex);
|
|
|
|
std::pair<book_container::iterator,book_container::iterator> rng;
|
|
if(author.empty()){
|
|
rng=std::make_pair(pbc->begin(),pbc->end());
|
|
}
|
|
else{
|
|
rng=pbc->equal_range(
|
|
shared_string(
|
|
author.c_str(),
|
|
shared_string::allocator_type(seg.get_segment_manager())));
|
|
}
|
|
|
|
if(rng.first==rng.second){
|
|
std::cout<<"no entries\n";
|
|
}
|
|
else{
|
|
std::copy(
|
|
rng.first,rng.second,std::ostream_iterator<book>(std::cout));
|
|
}
|
|
break;
|
|
}
|
|
case 2:{ /* list all books by prize */
|
|
bip::scoped_lock<bip::named_mutex> lock(mutex);
|
|
|
|
std::copy(
|
|
get<2>(*pbc).begin(),get<2>(*pbc).end(),
|
|
std::ostream_iterator<book>(std::cout));
|
|
break;
|
|
}
|
|
case 3:{ /* insert a book */
|
|
book b(shared_string::allocator_type(seg.get_segment_manager()));
|
|
|
|
enter("author: ",b.author);
|
|
enter("name: " ,b.name);
|
|
enter("prize: " ,b.prize);
|
|
enter("pages: " ,b.pages);
|
|
|
|
std::cout<<"insert the following?\n"<<b<<"(y/n): ";
|
|
char yn='n';
|
|
enter("",yn);
|
|
if(yn=='y'||yn=='Y'){
|
|
bip::scoped_lock<bip::named_mutex> lock(mutex);
|
|
pbc->insert(b);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case 4:{ /* delete a book */
|
|
shared_string name(
|
|
shared_string::allocator_type(seg.get_segment_manager()));
|
|
enter(
|
|
"name of the book (you can enter\nonly the first few characters): ",
|
|
name);
|
|
|
|
typedef nth_index<book_container,1>::type index_by_name;
|
|
index_by_name& idx=get<1>(*pbc);
|
|
index_by_name::iterator it;
|
|
book b(shared_string::allocator_type(seg.get_segment_manager()));
|
|
|
|
{
|
|
/* Look for a book whose title begins with name. Note that we
|
|
* are unlocking after doing the search so as to not leave the
|
|
* container blocked during user prompting. That is also why a
|
|
* local copy of the book is done.
|
|
*/
|
|
|
|
bip::scoped_lock<bip::named_mutex> lock(mutex);
|
|
|
|
it=idx.find(partial_string(name));
|
|
if(it==idx.end()){
|
|
std::cout<<"no such book found\n";
|
|
break;
|
|
}
|
|
b=*it;
|
|
}
|
|
|
|
std::cout<<"delete the following?\n"<<b<<"(y/n): ";
|
|
char yn='n';
|
|
enter("",yn);
|
|
if(yn=='y'||yn=='Y'){
|
|
bip::scoped_lock<bip::named_mutex> lock(mutex);
|
|
idx.erase(it);
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:{
|
|
std::cout<<"select one option:\n"<<command_info;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|