complex_structs.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /* Boost.MultiIndex example: complex searches and foreign keys.
  2. *
  3. * Copyright 2003-2008 Joaquin M Lopez Munoz.
  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. #if !defined(NDEBUG)
  11. #define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
  12. #define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
  13. #endif
  14. #include <boost/multi_index_container.hpp>
  15. #include <boost/multi_index/member.hpp>
  16. #include <boost/multi_index/ordered_index.hpp>
  17. #include <boost/tuple/tuple.hpp>
  18. #include <iostream>
  19. #include <string>
  20. using boost::multi_index_container;
  21. using namespace boost::multi_index;
  22. /* This small utility that cascades two key extractors will be
  23. * used througout the example.
  24. */
  25. template<class KeyExtractor1,class KeyExtractor2>
  26. struct key_from_key
  27. {
  28. public:
  29. typedef typename KeyExtractor1::result_type result_type;
  30. key_from_key(
  31. const KeyExtractor1& key1_=KeyExtractor1(),
  32. const KeyExtractor2& key2_=KeyExtractor2()):
  33. key1(key1_),key2(key2_)
  34. {}
  35. template<typename Arg>
  36. result_type operator()(Arg& arg)const
  37. {
  38. return key1(key2(arg));
  39. }
  40. private:
  41. KeyExtractor1 key1;
  42. KeyExtractor2 key2;
  43. };
  44. /* tags for accessing several indices defined below */
  45. struct model{};
  46. struct manufacturer{};
  47. struct price{};
  48. /* a manufacturer struct just holds the name of the manufacturer */
  49. struct car_manufacturer
  50. {
  51. std::string name;
  52. car_manufacturer(const std::string& name_):name(name_){}
  53. };
  54. /* car_model holds the model of car, its price and a pointer to the
  55. * manufacturer. The pointer thing eliminates duplication of the same
  56. * data among cars of the same manufacturer.
  57. */
  58. struct car_model
  59. {
  60. std::string model;
  61. const car_manufacturer* manufacturer;
  62. int price;
  63. car_model(
  64. const std::string& model_,const car_manufacturer* manufacturer_,int price_):
  65. model(model_),manufacturer(manufacturer_),price(price_)
  66. {}
  67. friend std::ostream& operator<<(std::ostream& os,const car_model& c)
  68. {
  69. os<<c.manufacturer->name<<" "<<c.model<<" $"<<c.price<<std::endl;
  70. return os;
  71. }
  72. };
  73. /* see Compiler specifics: Use of member_offset for info on
  74. * BOOST_MULTI_INDEX_MEMBER
  75. */
  76. /* Car manufacturers are stored in a multi_index_container with one single
  77. * index on the name member. This is functionally equivalent to an std::set,
  78. * though in this latter case we woud have to define a non-default comparison
  79. * predicate (with multi_index_container, member<> does the work for us.)
  80. */
  81. typedef multi_index_container<
  82. car_manufacturer,
  83. indexed_by<
  84. ordered_unique<
  85. BOOST_MULTI_INDEX_MEMBER(car_manufacturer,std::string,name)
  86. >
  87. >
  88. > car_manufacturer_table;
  89. /* Define a multi_index_container of car_models with following indices:
  90. * - a unique index sorted by car_model::model,
  91. * - a non-unique index sorted by car_model::manufacturer; note the
  92. * non-standard manufacturer_extractor used.
  93. * - a non-unique index sorted by car_model::price.
  94. */
  95. typedef multi_index_container<
  96. car_model,
  97. indexed_by<
  98. ordered_unique<
  99. tag<model>,BOOST_MULTI_INDEX_MEMBER(car_model,std::string,model)
  100. >,
  101. ordered_non_unique<
  102. tag<manufacturer>,
  103. key_from_key<
  104. BOOST_MULTI_INDEX_MEMBER(car_manufacturer,const std::string,name),
  105. BOOST_MULTI_INDEX_MEMBER(
  106. car_model,const car_manufacturer *,manufacturer)
  107. >
  108. >,
  109. ordered_non_unique<
  110. tag<price>,BOOST_MULTI_INDEX_MEMBER(car_model,int,price)
  111. >
  112. >
  113. > car_table;
  114. /* We call a *view* to a multi_index_container storing pointers instead of
  115. * actual objects. These views are used in the complex search performed
  116. * in the program. Resorting to multi_index of pointers eliminates
  117. * unnecessary copying of objects, and provides us with an opportunity
  118. * to show how BOOST_MULTI_INDEX_MEMBER can be used with pointer
  119. * type elements.
  120. * car_table_price_view indexes (pointers to) car_models by price.
  121. */
  122. typedef multi_index_container<
  123. const car_model*,
  124. indexed_by<
  125. ordered_non_unique<BOOST_MULTI_INDEX_MEMBER(car_model,const int,price)>
  126. >
  127. > car_table_price_view;
  128. /* car_table_manufacturer_view indexes (pointers to) car_models by
  129. * manufacturer
  130. */
  131. typedef multi_index_container<
  132. const car_model*,
  133. indexed_by<
  134. ordered_non_unique<
  135. key_from_key<
  136. BOOST_MULTI_INDEX_MEMBER(car_manufacturer,const std::string,name),
  137. BOOST_MULTI_INDEX_MEMBER(
  138. car_model,const car_manufacturer * const,manufacturer)
  139. >
  140. >
  141. >
  142. > car_table_manufacturer_view;
  143. int main()
  144. {
  145. car_manufacturer_table cmt;
  146. /* Fill the car_manufacturer table and keep pointers to the
  147. * elements inserted.
  148. */
  149. const car_manufacturer * cadillac=
  150. &*(cmt.insert(car_manufacturer("Cadillac")).first);
  151. const car_manufacturer * ford =
  152. &*(cmt.insert(car_manufacturer("Ford")).first);
  153. const car_manufacturer * bmw =
  154. &*(cmt.insert(car_manufacturer("BMW")).first);
  155. const car_manufacturer * audi =
  156. &*(cmt.insert(car_manufacturer("Audi")).first);
  157. car_table ct;
  158. /* Fill the car_model_table. We use the previously initialized
  159. * pointers to the elements of cmt.
  160. */
  161. ct.insert(car_model("XLR",cadillac,76200));
  162. ct.insert(car_model("SRX",cadillac,38690));
  163. ct.insert(car_model("CTS",cadillac,30695));
  164. ct.insert(car_model("Escalade",cadillac,54770));
  165. ct.insert(car_model("ESV",cadillac,57195));
  166. ct.insert(car_model("EXT",cadillac,52045));
  167. ct.insert(car_model("Deville",cadillac,45195));
  168. ct.insert(car_model("Seville",cadillac,46330));
  169. ct.insert(car_model("ZX2",ford,15355));
  170. ct.insert(car_model("Thunderbird",ford,43995));
  171. ct.insert(car_model("Windstar",ford,35510));
  172. ct.insert(car_model("Focus",ford,19630));
  173. ct.insert(car_model("Taurus",ford,24290));
  174. ct.insert(car_model("Mustang",ford,39900));
  175. ct.insert(car_model("Crown Victoria",ford,30370));
  176. ct.insert(car_model("325i",bmw,27800));
  177. ct.insert(car_model("545i",bmw,54300));
  178. ct.insert(car_model("745i",bmw,68500));
  179. ct.insert(car_model("M3 coupe",bmw,46500));
  180. ct.insert(car_model("Z4 roadster 3.0i",bmw,40250));
  181. ct.insert(car_model("X5 4.4i",bmw,49950));
  182. ct.insert(car_model("A4 1.8T",audi,25940));
  183. ct.insert(car_model("TT Coupe",audi,33940));
  184. ct.insert(car_model("A6 3.0",audi,36640));
  185. ct.insert(car_model("Allroad quattro 2.7T",audi,40640));
  186. ct.insert(car_model("A8 L",audi,69190));
  187. std::cout<<"enter a car manufacturer"<<std::endl;
  188. std::string cm;
  189. std::getline(std::cin,cm);
  190. /* check for manufacturer */
  191. car_manufacturer_table::iterator icm=cmt.find(cm);
  192. if(icm==cmt.end()){
  193. std::cout<<"no such manufacturer in the table"<<std::endl;
  194. return 0;
  195. }
  196. std::cout<<"enter a minimum price"<<std::endl;
  197. int min_price;
  198. std::cin>>min_price;
  199. std::cout<<"enter a maximum price"<<std::endl;
  200. int max_price;
  201. std::cin>>max_price;
  202. {
  203. /* method 1 */
  204. /* find all the cars for the manufacturer given */
  205. boost::multi_index::index<car_table,manufacturer>::type::iterator ic0,ic1;
  206. boost::tuples::tie(ic0,ic1)=get<manufacturer>(ct).equal_range(cm);
  207. /* construct a view (indexed by price) with these */
  208. car_table_price_view ctpv;
  209. while(ic0!=ic1){
  210. ctpv.insert(&*ic0);
  211. ++ic0;
  212. }
  213. /* select the cars in the range given */
  214. car_table_price_view::iterator ictpv0=ctpv.lower_bound(min_price);
  215. car_table_price_view::iterator ictpv1=ctpv.upper_bound(max_price);
  216. if(ictpv0==ictpv1){
  217. std::cout<<"no cars in the range given"<<std::endl;
  218. return 0;
  219. }
  220. /* list them */
  221. std::cout<<"listing by method 1"<<std::endl;
  222. while(ictpv0!=ictpv1){
  223. std::cout<<**ictpv0;
  224. ++ictpv0;
  225. }
  226. std::cout<<std::endl;
  227. }
  228. {
  229. /* method 2 will give the same results */
  230. /* find the cars in the range given */
  231. boost::multi_index::index<car_table,price>::type::iterator ic0,ic1;
  232. ic0=get<price>(ct).lower_bound(min_price);
  233. ic1=get<price>(ct).upper_bound(max_price);
  234. /* construct a view with these */
  235. car_table_manufacturer_view ctmv;
  236. while(ic0!=ic1){
  237. ctmv.insert(&*ic0);
  238. ++ic0;
  239. }
  240. /* select the cars with given manufacturer */
  241. car_table_manufacturer_view::iterator ictmv0,ictmv1;
  242. boost::tuples::tie(ictmv0,ictmv1)=ctmv.equal_range(cm);
  243. if(ictmv0==ictmv1){
  244. std::cout<<"no cars in the range given"<<std::endl;
  245. return 0;
  246. }
  247. /* list them */
  248. std::cout<<"listing by method 2"<<std::endl;
  249. while(ictmv0!=ictmv1){
  250. std::cout<<**ictmv0;
  251. ++ictmv0;
  252. }
  253. std::cout<<std::endl;
  254. }
  255. return 0;
  256. }