Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/multi_index/example/composite_keys.cpp @ 45

Last change on this file since 45 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 8.0 KB
Line 
1/* Boost.MultiIndex example of composite keys.
2 *
3 * Copyright 2003-2005 Joaquín M López Muñoz.
4 * Distributed under the Boost Software License, Version 1.0.
5 * (See accompanying file LICENSE_1_0.txt or copy at
6 * http://www.boost.org/LICENSE_1_0.txt)
7 *
8 * See http://www.boost.org/libs/multi_index for library home page.
9 */
10
11#if !defined(NDEBUG)
12#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
13#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
14#endif
15
16#include <boost/call_traits.hpp>
17#include <boost/multi_index_container.hpp>
18#include <boost/multi_index/composite_key.hpp>
19#include <boost/multi_index/member.hpp>
20#include <boost/multi_index/ordered_index.hpp>
21#include <boost/tokenizer.hpp>
22#include <functional>
23#include <iostream>
24#include <iterator>
25#include <map>
26#include <string>
27
28using namespace boost::multi_index;
29
30/* A file record maintains some info on name and size as well
31 * as a pointer to the directory it belongs (null meaning the root
32 * directory.)
33 */
34
35struct file_entry
36{
37  file_entry(
38    std::string name_,unsigned size_,bool is_dir_,const file_entry* dir_):
39    name(name_),size(size_),is_dir(is_dir_),dir(dir_)
40  {}
41
42  std::string       name;
43  unsigned          size;
44  bool              is_dir;
45  const file_entry* dir;
46
47  friend std::ostream& operator<<(std::ostream& os,const file_entry& f)
48  {
49    os<<f.name<<"\t"<<f.size;
50    if(f.is_dir)os<<"\t <dir>";
51    return os;
52  }
53};
54
55/* A file system is just a multi_index_container of entries with indices on
56 * file and size. These indices are firstly ordered by directory, as commands
57 * work on a current directory basis. Composite keys are just fine to model
58 * this.
59 * NB: The use of derivation here instead of simple typedef is explained in
60 * Compiler specifics: type hiding.
61 */
62
63struct name_key:composite_key<
64  file_entry,
65  BOOST_MULTI_INDEX_MEMBER(file_entry,const file_entry*,dir),
66  BOOST_MULTI_INDEX_MEMBER(file_entry,std::string,name)
67>{};
68
69struct size_key:composite_key<
70  file_entry,
71  BOOST_MULTI_INDEX_MEMBER(file_entry,const file_entry* const,dir),
72  BOOST_MULTI_INDEX_MEMBER(file_entry,unsigned,size)
73>{};
74
75/* see Compiler specifics: composite_key in compilers without partial
76 * template specialization, for info on composite_key_result_less
77 */
78
79typedef multi_index_container<
80  file_entry,
81  indexed_by<
82    /* primary index sorted by name (inside the same directory) */
83    ordered_unique<
84      name_key
85#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
86      ,composite_key_result_less<name_key::result_type>
87#endif
88    >,
89    /* secondary index sorted by size (inside the same directory) */
90    ordered_non_unique<
91      size_key
92#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
93      ,composite_key_result_less<size_key::result_type>
94#endif
95    >
96  >
97> file_system;
98
99/* typedef's of the two indices of file_system */
100
101typedef nth_index<file_system,0>::type file_system_by_name;
102typedef nth_index<file_system,1>::type file_system_by_size;
103
104/* We build a rudimentary file system simulation out of some global
105 * info and a map of commands provided to the user.
106 */
107
108static file_system fs;                 /* the one and only file system */
109static file_system_by_name& fs_by_name=fs;         /* name index to fs */
110static file_system_by_size& fs_by_size=get<1>(fs); /* size index to fs */
111static const file_entry* current_dir=0;            /* root directory   */
112
113/* command framework */
114
115/* A command provides an execute memfun fed with the corresponding params
116 * (first param is stripped off as it serves to identify the command
117 * currently being used.)
118 */
119
120typedef boost::tokenizer<boost::char_separator<char> > command_tokenizer;
121
122class command
123{
124public:
125  virtual ~command(){}
126  virtual void execute(
127    command_tokenizer::iterator tok1,command_tokenizer::iterator tok2)=0;
128};
129
130/* available commands */
131
132/* cd: syntax cd [.|..|<directory>] */
133
134class command_cd:public command
135{
136public:
137  virtual void execute(
138    command_tokenizer::iterator tok1,command_tokenizer::iterator tok2)
139  {
140    if(tok1==tok2)return;
141    std::string dir=*tok1++;
142
143    if(dir==".")return;
144    if(dir==".."){
145      if(current_dir)current_dir=current_dir->dir;
146      return;
147    }
148
149    file_system_by_name::iterator it=fs.find(
150      boost::make_tuple(current_dir,dir));
151    if(it==fs.end()){
152      std::cout<<"non-existent directory"<<std::endl;
153      return;
154    }
155    if(!it->is_dir){
156      std::cout<<dir<<" is not a directory"<<std::endl;
157      return;
158    }
159    current_dir=&*it;
160  }
161};
162static command_cd cd;
163
164/* ls: syntax ls [-s] */
165
166class command_ls:public command
167{
168public:
169  virtual void execute(
170    command_tokenizer::iterator tok1,command_tokenizer::iterator tok2)
171  {
172    std::string option;
173    if(tok1!=tok2)option=*tok1++;
174
175    if(!option.empty()){
176      if(option!="-s"){
177        std::cout<<"incorrect parameter"<<std::endl;
178        return;
179      }
180
181      /* list by size */
182
183      file_system_by_size::iterator it0,it1;
184      boost::tie(it0,it1)=fs_by_size.equal_range(
185        boost::make_tuple(current_dir));
186      std::copy(it0,it1,std::ostream_iterator<file_entry>(std::cout,"\n"));
187
188      return;
189    }
190
191    /* list by name */
192
193    file_system_by_name::iterator it0,it1;
194    boost::tie(it0,it1)=fs.equal_range(boost::make_tuple(current_dir));
195    std::copy(it0,it1,std::ostream_iterator<file_entry>(std::cout,"\n"));
196  }
197};
198static command_ls ls;
199
200/* mkdir: syntax mkdir <directory> */
201
202class command_mkdir:public command
203{
204public:
205  virtual void execute(
206    command_tokenizer::iterator tok1,command_tokenizer::iterator tok2)
207  {
208    std::string dir;
209    if(tok1!=tok2)dir=*tok1++;
210
211    if(dir.empty()){
212      std::cout<<"missing parameter"<<std::endl;
213      return;
214    }
215
216    if(dir=="."||dir==".."){
217      std::cout<<"incorrect parameter"<<std::endl;
218      return;
219    }
220
221    if(!fs.insert(file_entry(dir,0,true,current_dir)).second){
222      std::cout<<"directory already exists"<<std::endl;
223      return;
224    }
225  }
226};
227static command_mkdir mkdir;
228
229/* table of commands, a map from command names to class command pointers */
230
231typedef std::map<std::string,command*> command_table;
232static command_table cmt;
233
234int main()
235{
236  /* fill the file system with some data */
237
238  file_system::iterator it0,it1;
239 
240  fs.insert(file_entry("usr.cfg",240,false,0));
241  fs.insert(file_entry("memo.txt",2430,false,0));
242  it0=fs.insert(file_entry("dev",0,true,0)).first;
243    fs.insert(file_entry("tty0",128,false,&*it0));
244    fs.insert(file_entry("tty1",128,false,&*it0));
245  it0=fs.insert(file_entry("usr",0,true,0)).first;
246    it1=fs.insert(file_entry("bin",0,true,&*it0)).first;
247      fs.insert(file_entry("bjam",172032,false,&*it1));
248  it0=fs.insert(file_entry("home",0,true,0)).first;
249    it1=fs.insert(file_entry("andy",0,true,&*it0)).first;
250      fs.insert(file_entry("logo.jpg",5345,false,&*it1)).first;
251      fs.insert(file_entry("foo.cpp",890,false,&*it1)).first;
252      fs.insert(file_entry("foo.hpp",93,false,&*it1)).first;
253      fs.insert(file_entry("foo.html",750,false,&*it1)).first;
254      fs.insert(file_entry("a.obj",12302,false,&*it1)).first;
255      fs.insert(file_entry(".bash_history",8780,false,&*it1)).first;
256    it1=fs.insert(file_entry("rachel",0,true,&*it0)).first;
257      fs.insert(file_entry("test.py",650,false,&*it1)).first;
258      fs.insert(file_entry("todo.txt",241,false,&*it1)).first;
259      fs.insert(file_entry(".bash_history",9510,false,&*it1)).first;
260
261  /* fill the command table */
262
263  cmt["cd"]   =&cd;
264  cmt["ls"]   =&ls;
265  cmt["mkdir"]=&mkdir;
266
267  /* main looop */
268
269  for(;;){
270    /* print out the current directory and the prompt symbol */
271
272    if(current_dir)std::cout<<current_dir->name;
273    std::cout<<">";
274
275    /* get an input line from the user: if empty, exit the program */
276
277    std::string com;
278    std::getline(std::cin,com);
279    command_tokenizer tok(com,boost::char_separator<char>(" \t\n"));
280    if(tok.begin()==tok.end())break; /* null command, exit */
281
282    /* select the corresponding command and execute it */
283
284    command_table::iterator it=cmt.find(*tok.begin());
285    if(it==cmt.end()){
286      std::cout<<"invalid command"<<std::endl;
287      continue;
288    }
289
290    it->second->execute(++tok.begin(),tok.end());
291  }
292 
293  return 0;
294}
Note: See TracBrowser for help on using the repository browser.