doc_assoc_optimized_code.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2006-2013
  4. //
  5. // Distributed under the Boost Software License, Version 1.0.
  6. // (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // See http://www.boost.org/libs/intrusive for documentation.
  10. //
  11. /////////////////////////////////////////////////////////////////////////////
  12. //[doc_assoc_optimized_code_normal_find
  13. #include <boost/intrusive/set.hpp>
  14. #include <boost/intrusive/unordered_set.hpp>
  15. #include <cstring>
  16. using namespace boost::intrusive;
  17. // Hash function for strings
  18. struct StrHasher
  19. {
  20. std::size_t operator()(const char *str) const
  21. {
  22. std::size_t seed = 0;
  23. for(; *str; ++str) boost::hash_combine(seed, *str);
  24. return seed;
  25. }
  26. };
  27. class Expensive : public set_base_hook<>, public unordered_set_base_hook<>
  28. {
  29. std::string key_;
  30. // Other members...
  31. public:
  32. Expensive(const char *key)
  33. : key_(key)
  34. {} //other expensive initializations...
  35. const std::string & get_key() const
  36. { return key_; }
  37. friend bool operator < (const Expensive &a, const Expensive &b)
  38. { return a.key_ < b.key_; }
  39. friend bool operator == (const Expensive &a, const Expensive &b)
  40. { return a.key_ == b.key_; }
  41. friend std::size_t hash_value(const Expensive &object)
  42. { return StrHasher()(object.get_key().c_str()); }
  43. };
  44. // A set and unordered_set that store Expensive objects
  45. typedef set<Expensive> Set;
  46. typedef unordered_set<Expensive> UnorderedSet;
  47. // Search functions
  48. Expensive *get_from_set(const char* key, Set &set_object)
  49. {
  50. Set::iterator it = set_object.find(Expensive(key));
  51. if( it == set_object.end() ) return 0;
  52. return &*it;
  53. }
  54. Expensive *get_from_uset(const char* key, UnorderedSet &uset_object)
  55. {
  56. UnorderedSet::iterator it = uset_object.find(Expensive (key));
  57. if( it == uset_object.end() ) return 0;
  58. return &*it;
  59. }
  60. //]
  61. //[doc_assoc_optimized_code_optimized_find
  62. // These compare Expensive and a c-string
  63. struct StrExpComp
  64. {
  65. bool operator()(const char *str, const Expensive &c) const
  66. { return std::strcmp(str, c.get_key().c_str()) < 0; }
  67. bool operator()(const Expensive &c, const char *str) const
  68. { return std::strcmp(c.get_key().c_str(), str) < 0; }
  69. };
  70. struct StrExpEqual
  71. {
  72. bool operator()(const char *str, const Expensive &c) const
  73. { return std::strcmp(str, c.get_key().c_str()) == 0; }
  74. bool operator()(const Expensive &c, const char *str) const
  75. { return std::strcmp(c.get_key().c_str(), str) == 0; }
  76. };
  77. // Optimized search functions
  78. Expensive *get_from_set_optimized(const char* key, Set &set_object)
  79. {
  80. Set::iterator it = set_object.find(key, StrExpComp());
  81. if( it == set_object.end() ) return 0;
  82. return &*it;
  83. }
  84. Expensive *get_from_uset_optimized(const char* key, UnorderedSet &uset_object)
  85. {
  86. UnorderedSet::iterator it = uset_object.find(key, StrHasher(), StrExpEqual());
  87. if( it == uset_object.end() ) return 0;
  88. return &*it;
  89. }
  90. //]
  91. //[doc_assoc_optimized_code_normal_insert
  92. // Insertion functions
  93. bool insert_to_set(const char* key, Set &set_object)
  94. {
  95. Expensive *pobject = new Expensive(key);
  96. bool success = set_object.insert(*pobject).second;
  97. if(!success) delete pobject;
  98. return success;
  99. }
  100. bool insert_to_uset(const char* key, UnorderedSet &uset_object)
  101. {
  102. Expensive *pobject = new Expensive(key);
  103. bool success = uset_object.insert(*pobject).second;
  104. if(!success) delete pobject;
  105. return success;
  106. }
  107. //]
  108. //[doc_assoc_optimized_code_optimized_insert
  109. // Optimized insertion functions
  110. bool insert_to_set_optimized(const char* key, Set &set_object)
  111. {
  112. Set::insert_commit_data insert_data;
  113. bool success = set_object.insert_check(key, StrExpComp(), insert_data).second;
  114. if(success) set_object.insert_commit(*new Expensive(key), insert_data);
  115. return success;
  116. }
  117. bool insert_to_uset_optimized(const char* key, UnorderedSet &uset_object)
  118. {
  119. UnorderedSet::insert_commit_data insert_data;
  120. bool success = uset_object.insert_check
  121. (key, StrHasher(), StrExpEqual(), insert_data).second;
  122. if(success) uset_object.insert_commit(*new Expensive(key), insert_data);
  123. return success;
  124. }
  125. //]
  126. int main()
  127. {
  128. Set set;
  129. UnorderedSet::bucket_type buckets[10];
  130. UnorderedSet unordered_set(UnorderedSet::bucket_traits(buckets, 10));
  131. const char * const expensive_key
  132. = "A long string that avoids small string optimization";
  133. Expensive value(expensive_key);
  134. if(get_from_set(expensive_key, set)){
  135. return 1;
  136. }
  137. if(get_from_uset(expensive_key, unordered_set)){
  138. return 1;
  139. }
  140. if(get_from_set_optimized(expensive_key, set)){
  141. return 1;
  142. }
  143. if(get_from_uset_optimized(expensive_key, unordered_set)){
  144. return 1;
  145. }
  146. Set::iterator setit = set.insert(value).first;
  147. UnorderedSet::iterator unordered_setit = unordered_set.insert(value).first;
  148. if(!get_from_set(expensive_key, set)){
  149. return 1;
  150. }
  151. if(!get_from_uset(expensive_key, unordered_set)){
  152. return 1;
  153. }
  154. if(!get_from_set_optimized(expensive_key, set)){
  155. return 1;
  156. }
  157. if(!get_from_uset_optimized(expensive_key, unordered_set)){
  158. return 1;
  159. }
  160. set.erase(setit);
  161. unordered_set.erase(unordered_setit);
  162. if(!insert_to_set(expensive_key, set)){
  163. return 1;
  164. }
  165. if(!insert_to_uset(expensive_key, unordered_set)){
  166. return 1;
  167. }
  168. {
  169. Expensive *ptr = &*set.begin();
  170. set.clear();
  171. delete ptr;
  172. }
  173. {
  174. Expensive *ptr = &*unordered_set.begin();
  175. unordered_set.clear();
  176. delete ptr;
  177. }
  178. if(!insert_to_set_optimized(expensive_key, set)){
  179. return 1;
  180. }
  181. if(!insert_to_uset_optimized(expensive_key, unordered_set)){
  182. return 1;
  183. }
  184. {
  185. Expensive *ptr = &*set.begin();
  186. set.clear();
  187. delete ptr;
  188. }
  189. {
  190. Expensive *ptr = &*unordered_set.begin();
  191. unordered_set.clear();
  192. delete ptr;
  193. }
  194. setit = set.insert(value).first;
  195. unordered_setit = unordered_set.insert(value).first;
  196. if(insert_to_set(expensive_key, set)){
  197. return 1;
  198. }
  199. if(insert_to_uset(expensive_key, unordered_set)){
  200. return 1;
  201. }
  202. if(insert_to_set_optimized(expensive_key, set)){
  203. return 1;
  204. }
  205. if(insert_to_uset_optimized(expensive_key, unordered_set)){
  206. return 1;
  207. }
  208. set.erase(value);
  209. unordered_set.erase(value);
  210. return 0;
  211. }