associative_mapper.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /************************************************************************************
  2. * *
  3. * Copyright (c) 2014 - 2018 Axel Menzel <info@rttr.org> *
  4. * *
  5. * This file is part of RTTR (Run Time Type Reflection) *
  6. * License: MIT License *
  7. * *
  8. * Permission is hereby granted, free of charge, to any person obtaining *
  9. * a copy of this software and associated documentation files (the "Software"), *
  10. * to deal in the Software without restriction, including without limitation *
  11. * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  12. * and/or sell copies of the Software, and to permit persons to whom the *
  13. * Software is furnished to do so, subject to the following conditions: *
  14. * *
  15. * The above copyright notice and this permission notice shall be included in *
  16. * all copies or substantial portions of the Software. *
  17. * *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE *
  24. * SOFTWARE. *
  25. * *
  26. *************************************************************************************/
  27. #ifndef RTTR_ASSOCIATIVE_MAPPER_H_
  28. #define RTTR_ASSOCIATIVE_MAPPER_H_
  29. #include "rttr/detail/base/core_prerequisites.h"
  30. namespace rttr
  31. {
  32. /*!
  33. * The \ref associative_container_mapper class is a class template to access an associative container via one common interface.
  34. *
  35. * This class will be only used internally by RTTR via the variant_associative_view class to get access to elements of an associative container.
  36. * In order to use your own custom associative container type, you have to provide a specialization of this class.
  37. *
  38. * Out of the box, RTTR has specialization for following associative container types:
  39. * - \p `std::set<Key>`
  40. * - \p `std::map<Key, T>`
  41. * - \p `std::multiset<Key>`
  42. * - \p `std::multimap<Key, T>`
  43. * - \p `std::unordered_set<Key>`
  44. * - \p `std::unordered_map<Key, T>`
  45. * - \p `std::unordered_multiset<Key>`
  46. * - \p `std::unordered_multimap<Key, T>`
  47. *
  48. * Custom associative container
  49. * -----------------------------
  50. * For a specialization of the class \ref rttr::associative_container_mapper<T> "associative_container_mapper<T>"
  51. * you have to provide some nested alias templates:
  52. * 1. `using container_t = T;`
  53. * 2. `using key_t = typename T::key_type;`
  54. * 3. `using value_t = typename T::mapped_type;` \remark When you have a key-only container, like `std::set<T>`, use `void`; i.e. `using value_t = void;`
  55. * 4. `using itr_t = typename T::iterator;`
  56. * 5. `using const_itr_t = typename T::const_iterator;`
  57. *
  58. * and following member functions:
  59. * 1. `static const key_t& get_key(const const_itr_t& itr);`
  60. * 2. `static value_t& get_value(itr_t& itr);`
  61. * 3. `static const value_t& get_value(const const_itr_t& itr);`
  62. * 4. `static itr_t begin(container_t& container);`
  63. * 5. `static const_itr_t begin(const container_t& container);`
  64. * 6. `static const_itr_t end(const container_t& container);`
  65. * 7. `static itr_t find(container_t& container, const key_t& key);`
  66. * 8. `static const_itr_t find(const container_t& container, const key_t& key);`
  67. * 9. `static std::pair<itr_t, itr_t> equal_range(container_t& container, const key_t& key);`
  68. * 10. `static std::pair<const_itr_t, const_itr_t> equal_range(const container_t& container, const key_t& key);`
  69. * 11. `static void clear(container_t& container);`
  70. * 13. `static bool is_empty(const container_t& container);`
  71. * 14. `static std::size_t get_size(const container_t& container);`
  72. * 15. `static std::size_t erase(container_t& container, const key_t& key);`
  73. * 16. `static std::pair<itr_t, bool> insert_key(container_t& container, const key_t& key);`
  74. * \remark This method needs to be implemented only when you have a key-only container.
  75. * 17. `static std::pair<itr_t, bool> insert_key_value(container_t& container, const key_t& key, const value_t& value);`
  76. * \remark This method needs to be implemented only when you have a key-value container.
  77. *
  78. * Following code example for the associative container <a target="_blank" href=http://doc.qt.io/qt-5/qhash.html>QHash<K, T></a>
  79. * illustrates how to add a specialization:
  80. *
  81. * \code{.cpp}
  82. * namespace rttr
  83. * {
  84. * template<typename K, typename T>
  85. * struct associative_container_mapper<QHash<K, T>>
  86. * {
  87. * using container_t = QHash<K, T>;
  88. * using key_t = typename QHash<K, T>::key_type;
  89. * using value_t = typename QHash<K, T>::mapped_type;
  90. * using itr_t = typename QHash<K, T>::iterator;
  91. * using const_itr_t = typename QHash<K, T>::const_iterator;
  92. *
  93. * static const key_t& get_key(const const_itr_t& itr)
  94. * {
  95. * return itr.key();
  96. * }
  97. *
  98. * static value_t& get_value(itr_t& itr)
  99. * {
  100. * return itr.value();
  101. * }
  102. *
  103. * static const value_t& get_value(const const_itr_t& itr)
  104. * {
  105. * return itr.value();
  106. * }
  107. *
  108. * static itr_t begin(container_t& container)
  109. * {
  110. * return container.begin();
  111. * }
  112. *
  113. * static const_itr_t begin(const container_t& container)
  114. * {
  115. * return container.begin();
  116. * }
  117. *
  118. * static itr_t end(container_t& container)
  119. * {
  120. * return container.end();
  121. * }
  122. *
  123. * static const_itr_t end(const container_t& container)
  124. * {
  125. * return container.end();
  126. * }
  127. *
  128. * static itr_t find(container_t& container, key_t& key)
  129. * {
  130. * return container.find(key);
  131. * }
  132. *
  133. * static const_itr_t find(const container_t& container, key_t& key)
  134. * {
  135. * return container.find(key);
  136. * }
  137. *
  138. * static std::pair<itr_t, itr_t> equal_range(container_t& container, key_t& key)
  139. * {
  140. * auto ret = container.equal_range(key);
  141. * return std::make_pair(ret.first, ret.second);
  142. * }
  143. *
  144. * static std::pair<const_itr_t, const_itr_t> equal_range(const container_t& container, key_t& key)
  145. * {
  146. * auto ret = container.equal_range(key);
  147. * return std::make_pair(ret.first, ret.second);
  148. * }
  149. *
  150. * static void clear(container_t& container)
  151. * {
  152. * container.clear();
  153. * }
  154. *
  155. * static bool is_empty(const container_t& container)
  156. * {
  157. * return container.isEmpty();
  158. * }
  159. *
  160. * static std::size_t get_size(const container_t& container)
  161. * {
  162. * return container.size();
  163. * }
  164. *
  165. * static std::size_t erase(container_t& container, key_t& key)
  166. * {
  167. * return container.remove(key);
  168. * }
  169. *
  170. * static std::pair<itr_t, bool> insert_key_value(container_t& container, key_t& key, value_t& value)
  171. * {
  172. * return std::make_pair(container.insert(key, value), true);
  173. * }
  174. * };
  175. * } // end namespace rttr
  176. * \endcode
  177. *
  178. * \remark
  179. * Make sure you put your specialization inside the namespace `rttr`.
  180. * The best place for this code, is below the declaration of your custom associative container type.
  181. * When this is not possible, include your specialization code before registering your types to RTTR.
  182. */
  183. template<typename T>
  184. struct associative_container_mapper
  185. {
  186. #ifndef DOXYGEN
  187. using is_valid = std::false_type;
  188. #else
  189. using container_t = T; //!< An alias declaration to the container type itself.
  190. using key_t = typename T::key_type; //!< An alias to the key type.
  191. using value_t = typename T::mapped_type; //!< An alias to the value type.
  192. //!< \remark When you have a key only container use `void` as value type.
  193. //!< Then you also dont need to add a insert_key_value() function
  194. using itr_t = typename T::iterator; //!< An alias delcaration to the iterator.
  195. using const_itr_t = typename T::const_iterator; //!< An alias delcaration to the const iterator.
  196. /////////////////////////////////////////////////////////////////////////////////////
  197. /*!
  198. * \brief Returns the current iterator's key as a const reference.
  199. */
  200. static const key_t& get_key(const const_itr_t& itr)
  201. {
  202. return itr->first;
  203. }
  204. /////////////////////////////////////////////////////////////////////////////////////
  205. /*!
  206. * \brief Returns the current iterator's value as reference.
  207. */
  208. static value_t& get_value(itr_t& itr)
  209. {
  210. return itr->second;
  211. }
  212. /*!
  213. * \brief Returns the current iterator's value as const reference.
  214. */
  215. static const value_t& get_value(const const_itr_t& itr)
  216. {
  217. return itr->second;
  218. }
  219. /////////////////////////////////////////////////////////////////////////////////////
  220. /*!
  221. * \brief Returns an iterator to the first element of the container.
  222. */
  223. static itr_t begin(container_t& container)
  224. {
  225. return container.begin();
  226. }
  227. /*!
  228. * \brief Returns an iterator to the first element of the container.
  229. */
  230. static const_itr_t begin(const container_t& container)
  231. {
  232. return container.begin();
  233. }
  234. /////////////////////////////////////////////////////////////////////////////////////
  235. /*!
  236. * \brief Returns an iterator to the element following the last element of the container.
  237. */
  238. static itr_t end(container_t& container)
  239. {
  240. return container.end();
  241. }
  242. /*!
  243. * \brief Returns an iterator to the element following the last element of the container.
  244. */
  245. static const_itr_t end(const container_t& container)
  246. {
  247. return container.end();
  248. }
  249. /////////////////////////////////////////////////////////////////////////////////////
  250. /*!
  251. * \brief Finds an element with key equivalent to key and returns its iterator.
  252. */
  253. static itr_t find(container_t& container, const key_t& key)
  254. {
  255. return container.find(key);
  256. }
  257. /*!
  258. * \brief Finds an element with key equivalent to key and returns its iterator.
  259. */
  260. static const_itr_t find(const container_t& container, const key_t& key)
  261. {
  262. return container.find(key);
  263. }
  264. /////////////////////////////////////////////////////////////////////////////////////
  265. /*!
  266. * \brief Returns a range containing all elements with the given key in the container.
  267. * The range is defined by two iterators, one pointing to the first element that
  268. * is not less than key and another pointing to the first element greater than key.
  269. */
  270. static std::pair<itr_t, itr_t> equal_range(container_t& container, const key_t& key)
  271. {
  272. return container.equal_range(key);
  273. }
  274. /*!
  275. * \brief Returns a range containing all elements with the given key in the container.
  276. * The range is defined by two constant iterators, one pointing to the first element that
  277. * is not less than key and another pointing to the first element greater than key.
  278. */
  279. static std::pair<const_itr_t, const_itr_t> equal_range(const container_t& container, const key_t& key)
  280. {
  281. return container.equal_range(key);
  282. }
  283. /////////////////////////////////////////////////////////////////////////////////////
  284. /*!
  285. * \brief Removes all elements from the container.
  286. */
  287. static void clear(container_t& container)
  288. {
  289. container.clear();
  290. }
  291. /*!
  292. * \brief Returns the number of elements in the container.
  293. */
  294. static bool is_empty(const container_t& container)
  295. {
  296. return container.empty();
  297. }
  298. /*!
  299. * \brief Returns the number of elements in the container.
  300. */
  301. static std::size_t get_size(const container_t& container)
  302. {
  303. return container.size();
  304. }
  305. /*!
  306. * \brief Removes the element (if one exists) with the key equivalent to key.
  307. */
  308. static std::size_t erase(container_t& container, const key_t& key)
  309. {
  310. return container.erase(key);
  311. }
  312. /*!
  313. * \brief Inserts a key into the container.
  314. * \remark This method is only necessary, when you have a key-only container. Like `std::set<T>`.
  315. * Otherwise you don't need to declare it.
  316. */
  317. static std::pair<itr_t, bool> insert_key(container_t& container, const key_t& key)
  318. {
  319. return { container.end(), false };
  320. }
  321. /*!
  322. * \brief Inserts a key-value into the container.
  323. * \remark This method is only necessary, when you have a key-value container. Like `std::map<T>`.
  324. * Otherwise you don't need to declare it.
  325. */
  326. static std::pair<itr_t, bool> insert_key_value(container_t& container, const key_t& key, const value_t& value)
  327. {
  328. return container.insert(std::make_pair(key, value));
  329. }
  330. #endif
  331. };
  332. } // end namespace rttr
  333. #include "rttr/detail/impl/associative_mapper_impl.h"
  334. #endif // RTTR_ASSOCIATIVE_MAPPER_H_