/* Boost.MultiIndex example of composite keys. * * 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 #include #include #include #include #include #include #include #include #include #include #include using namespace boost::multi_index; /* A file record maintains some info on name and size as well * as a pointer to the directory it belongs (null meaning the root * directory.) */ struct file_entry { file_entry( std::string name_,unsigned size_,bool is_dir_,const file_entry* dir_): name(name_),size(size_),is_dir(is_dir_),dir(dir_) {} std::string name; unsigned size; bool is_dir; const file_entry* dir; friend std::ostream& operator<<(std::ostream& os,const file_entry& f) { os<"; return os; } }; /* A file system is just a multi_index_container of entries with indices on * file and size. These indices are firstly ordered by directory, as commands * work on a current directory basis. Composite keys are just fine to model * this. * NB: The use of derivation here instead of simple typedef is explained in * Compiler specifics: type hiding. */ struct name_key:composite_key< file_entry, BOOST_MULTI_INDEX_MEMBER(file_entry,const file_entry*,dir), BOOST_MULTI_INDEX_MEMBER(file_entry,std::string,name) >{}; struct size_key:composite_key< file_entry, BOOST_MULTI_INDEX_MEMBER(file_entry,const file_entry* const,dir), BOOST_MULTI_INDEX_MEMBER(file_entry,unsigned,size) >{}; /* see Compiler specifics: composite_key in compilers without partial * template specialization, for info on composite_key_result_less */ typedef multi_index_container< file_entry, indexed_by< /* primary index sorted by name (inside the same directory) */ ordered_unique, /* secondary index sorted by size (inside the same directory) */ ordered_non_unique > > file_system; /* typedef's of the two indices of file_system */ typedef nth_index::type file_system_by_name; typedef nth_index::type file_system_by_size; /* We build a rudimentary file system simulation out of some global * info and a map of commands provided to the user. */ static file_system fs; /* the one and only file system */ static file_system_by_name& fs_by_name=fs; /* name index to fs */ static file_system_by_size& fs_by_size=get<1>(fs); /* size index to fs */ static const file_entry* current_dir=0; /* root directory */ /* command framework */ /* A command provides an execute memfun fed with the corresponding params * (first param is stripped off as it serves to identify the command * currently being used.) */ typedef boost::tokenizer > command_tokenizer; class command { public: virtual ~command(){} virtual void execute( command_tokenizer::iterator tok1,command_tokenizer::iterator tok2)=0; }; /* available commands */ /* cd: syntax cd [.|..|] */ class command_cd:public command { public: virtual void execute( command_tokenizer::iterator tok1,command_tokenizer::iterator tok2) { if(tok1==tok2)return; std::string dir=*tok1++; if(dir==".")return; if(dir==".."){ if(current_dir)current_dir=current_dir->dir; return; } file_system_by_name::iterator it=fs.find( boost::make_tuple(current_dir,dir)); if(it==fs.end()){ std::cout<<"non-existent directory"<is_dir){ std::cout<(std::cout,"\n")); return; } /* list by name */ file_system_by_name::iterator it0,it1; boost::tie(it0,it1)=fs.equal_range(boost::make_tuple(current_dir)); std::copy(it0,it1,std::ostream_iterator(std::cout,"\n")); } }; static command_ls ls; /* mkdir: syntax mkdir */ class command_mkdir:public command { public: virtual void execute( command_tokenizer::iterator tok1,command_tokenizer::iterator tok2) { std::string dir; if(tok1!=tok2)dir=*tok1++; if(dir.empty()){ std::cout<<"missing parameter"< command_table; static command_table cmt; int main() { /* fill the file system with some data */ file_system::iterator it0,it1; fs.insert(file_entry("usr.cfg",240,false,0)); fs.insert(file_entry("memo.txt",2430,false,0)); it0=fs.insert(file_entry("dev",0,true,0)).first; fs.insert(file_entry("tty0",128,false,&*it0)); fs.insert(file_entry("tty1",128,false,&*it0)); it0=fs.insert(file_entry("usr",0,true,0)).first; it1=fs.insert(file_entry("bin",0,true,&*it0)).first; fs.insert(file_entry("bjam",172032,false,&*it1)); it0=fs.insert(file_entry("home",0,true,0)).first; it1=fs.insert(file_entry("andy",0,true,&*it0)).first; fs.insert(file_entry("logo.jpg",5345,false,&*it1)).first; fs.insert(file_entry("foo.cpp",890,false,&*it1)).first; fs.insert(file_entry("foo.hpp",93,false,&*it1)).first; fs.insert(file_entry("foo.html",750,false,&*it1)).first; fs.insert(file_entry("a.obj",12302,false,&*it1)).first; fs.insert(file_entry(".bash_history",8780,false,&*it1)).first; it1=fs.insert(file_entry("rachel",0,true,&*it0)).first; fs.insert(file_entry("test.py",650,false,&*it1)).first; fs.insert(file_entry("todo.txt",241,false,&*it1)).first; fs.insert(file_entry(".bash_history",9510,false,&*it1)).first; /* fill the command table */ cmt["cd"] =&cd; cmt["ls"] =&ls; cmt["mkdir"]=&mkdir; /* main looop */ for(;;){ /* print out the current directory and the prompt symbol */ if(current_dir)std::cout<name; std::cout<<">"; /* get an input line from the user: if empty, exit the program */ std::string com; std::getline(std::cin,com); command_tokenizer tok(com,boost::char_separator(" \t\n")); if(tok.begin()==tok.end())break; /* null command, exit */ /* select the corresponding command and execute it */ command_table::iterator it=cmt.find(*tok.begin()); if(it==cmt.end()){ std::cout<<"invalid command"<second->execute(boost::next(tok.begin()),tok.end()); } return 0; }