StlUtils.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. // Description : Various convenience utility functions for STL and alike
  9. // Used in Animation subsystem, and in some tools
  10. #pragma once
  11. #include <unordered_map>
  12. #include <unordered_set>
  13. #include <AzCore/std/allocator_stateless.h>
  14. #include <AzCore/std/containers/unordered_map.h>
  15. #include <AzCore/std/containers/unordered_set.h>
  16. #include <AzCore/std/string/string.h>
  17. #if (defined(LINUX) || defined(APPLE))
  18. #include "platform.h"
  19. #endif
  20. #define STATIC_ASSERT(condition, errMessage) static_assert(condition, errMessage)
  21. #include <cctype>
  22. #include <map>
  23. #include <set>
  24. #include <algorithm>
  25. #include <deque>
  26. #include <vector>
  27. #undef std__hash_map
  28. #define std__hash_map AZStd::unordered_map
  29. #define std__unordered_set AZStd::unordered_set
  30. #define std__hash_multimap AZStd::unordered_multimap
  31. #define std__hash AZStd::hash
  32. #define std__unordered_map AZStd::unordered_map
  33. // auto-cleaner: upon destruction, calls the clear() method
  34. template <class T>
  35. class CAutoClear
  36. {
  37. public:
  38. CAutoClear (T* p)
  39. : m_p(p) {}
  40. ~CAutoClear () {m_p->clear(); }
  41. protected:
  42. T* m_p;
  43. };
  44. template <class Container>
  45. unsigned sizeofArray (const Container& arr)
  46. {
  47. return (unsigned)(sizeof(typename Container::value_type) * arr.size());
  48. }
  49. template <class Container>
  50. unsigned sizeofVector (const Container& arr)
  51. {
  52. return (unsigned)(sizeof(typename Container::value_type) * arr.capacity());
  53. }
  54. template <class Container>
  55. unsigned sizeofArray (const Container& arr, unsigned nSize)
  56. {
  57. return arr.empty() ? 0u : (unsigned)(sizeof(typename Container::value_type) * nSize);
  58. }
  59. template <class Container>
  60. unsigned capacityofArray (const Container& arr)
  61. {
  62. return (unsigned)(arr.capacity() * sizeof(arr[0]));
  63. }
  64. template <class T>
  65. unsigned countElements (const std::vector<T>& arrT, const T& x)
  66. {
  67. unsigned nSum = 0;
  68. for (typename std::vector<T>::const_iterator iter = arrT.begin(); iter != arrT.end(); ++iter)
  69. {
  70. if (x == *iter)
  71. {
  72. ++nSum;
  73. }
  74. }
  75. return nSum;
  76. }
  77. // [Timur]
  78. /** Contain extensions for STL library.
  79. */
  80. namespace stl
  81. {
  82. //////////////////////////////////////////////////////////////////////////
  83. //! Searches the given entry in the map by key, and if there is none, returns the default value
  84. //////////////////////////////////////////////////////////////////////////
  85. template <typename Map>
  86. inline typename Map::mapped_type find_in_map(const Map& mapKeyToValue, const typename Map::key_type& key, typename Map::mapped_type valueDefault)
  87. {
  88. typename Map::const_iterator it = mapKeyToValue.find (key);
  89. if (it == mapKeyToValue.end())
  90. {
  91. return valueDefault;
  92. }
  93. else
  94. {
  95. return it->second;
  96. }
  97. }
  98. //////////////////////////////////////////////////////////////////////////
  99. //! Fills vector with contents of map.
  100. //////////////////////////////////////////////////////////////////////////
  101. template <class Map, class Vector>
  102. inline void map_to_vector(const Map& theMap, Vector& array)
  103. {
  104. array.resize(0);
  105. array.reserve(theMap.size());
  106. for (typename Map::const_iterator it = theMap.begin(); it != theMap.end(); ++it)
  107. {
  108. array.push_back(it->second);
  109. }
  110. }
  111. //////////////////////////////////////////////////////////////////////////
  112. //! Find and erase element from container.
  113. // @return true if item was find and erased, false if item not found.
  114. //////////////////////////////////////////////////////////////////////////
  115. template <class Container, class Value>
  116. inline bool find_and_erase(Container& container, const Value& value)
  117. {
  118. typename Container::iterator it = AZStd::find(container.begin(), container.end(), value);
  119. if (it != container.end())
  120. {
  121. container.erase(it);
  122. return true;
  123. }
  124. return false;
  125. }
  126. template <typename K, typename P, typename A>
  127. inline bool find_and_erase(std::set<K, P, A>& container, const K& value)
  128. {
  129. return container.erase(value) > 0;
  130. }
  131. //////////////////////////////////////////////////////////////////////////
  132. //! Find and erase element from container.
  133. // @return true if item was find and erased, false if item not found.
  134. //////////////////////////////////////////////////////////////////////////
  135. template <class CONTAINER, class PREDICATE>
  136. inline bool find_and_erase_if(CONTAINER& container, const PREDICATE& predicate)
  137. {
  138. typename CONTAINER::iterator end = container.end(), i = std::find_if(container.begin(), end, predicate);
  139. if (i != end)
  140. {
  141. container.erase(i);
  142. return true;
  143. }
  144. return false;
  145. }
  146. //////////////////////////////////////////////////////////////////////////
  147. //! Find and erase all elements matching value from container.
  148. // Assume that this will invalidate any exiting iterators.
  149. // Commonly used for removing NULL pointers from collections.
  150. //////////////////////////////////////////////////////////////////////////
  151. template <class Container>
  152. inline void find_and_erase_all(Container& container, const typename Container::value_type& value)
  153. {
  154. // Shuffles all elements != value to the front and returns the start of the removed elements.
  155. typename Container::iterator endIter(container.end());
  156. typename Container::iterator newEndIter(std::remove(container.begin(), endIter, value));
  157. // Delete the removed range at the back of the container (low-cost for vector).
  158. container.erase(newEndIter, endIter);
  159. }
  160. //////////////////////////////////////////////////////////////////////////
  161. //! Find and erase element from map.
  162. // @return true if item was find and erased, false if item not found.
  163. //////////////////////////////////////////////////////////////////////////
  164. template <class Container, class Key>
  165. inline bool member_find_and_erase(Container& container, const Key& key)
  166. {
  167. typename Container::iterator it = container.find (key);
  168. if (it != container.end())
  169. {
  170. container.erase(it);
  171. return true;
  172. }
  173. return false;
  174. }
  175. //////////////////////////////////////////////////////////////////////////
  176. //! Push back to container unique element.
  177. // @return true if item added, false overwise.
  178. template <class Container, class Value>
  179. inline bool push_back_unique(Container& container, const Value& value)
  180. {
  181. if (AZStd::find(container.begin(), container.end(), value) == container.end())
  182. {
  183. container.push_back(value);
  184. return true;
  185. }
  186. return false;
  187. }
  188. //////////////////////////////////////////////////////////////////////////
  189. //! Find element in container.
  190. // @return true if item found.
  191. template <class Container, class Value>
  192. inline bool find(Container& container, const Value& value)
  193. {
  194. return std::find(container.begin(), container.end(), value) != container.end();
  195. }
  196. //////////////////////////////////////////////////////////////////////////
  197. //! Find element in a sorted container using binary search with logarithmic efficiency.
  198. //
  199. template <class Iterator, class T>
  200. inline Iterator binary_find(Iterator first, Iterator last, const T& value)
  201. {
  202. Iterator it = std::lower_bound(first, last, value);
  203. return (it == last || value != *it) ? last : it;
  204. }
  205. struct container_object_deleter
  206. {
  207. template<typename T>
  208. void operator()(const T* ptr) const
  209. {
  210. delete ptr;
  211. }
  212. };
  213. //////////////////////////////////////////////////////////////////////////
  214. //! Convert arbitary class to const char*
  215. //////////////////////////////////////////////////////////////////////////
  216. template <class Type>
  217. inline const char* constchar_cast(const Type& type)
  218. {
  219. return type;
  220. }
  221. //! Specialization of string to const char cast.
  222. template <>
  223. inline const char* constchar_cast(const AZStd::basic_string<char, AZStd::char_traits<char>, AZStd::stateless_allocator>& type)
  224. {
  225. return type.c_str();
  226. }
  227. //! Specialization of string to const char cast.
  228. template <>
  229. inline const char* constchar_cast(const AZStd::string& type)
  230. {
  231. return type.c_str();
  232. }
  233. //////////////////////////////////////////////////////////////////////////
  234. //! Case insensetive less key for any type convertable to const char*.
  235. template <class Type>
  236. struct less_stricmp
  237. {
  238. bool operator()(const Type& left, const Type& right) const
  239. {
  240. return _stricmp(constchar_cast(left), constchar_cast(right)) < 0;
  241. }
  242. };
  243. //////////////////////////////////////////////////////////////////////////
  244. // Hash map usage:
  245. // typedef AZStd::unordered_map<string,int, stl::hash_string_insensitve<string>, stl::equality_string_insensitive<string> > StringToIntHash;
  246. //////////////////////////////////////////////////////////////////////////
  247. //////////////////////////////////////////////////////////////////////////
  248. //! Case sensitive string hash
  249. //////////////////////////////////////////////////////////////////////////
  250. template <class Key>
  251. class hash_string
  252. {
  253. public:
  254. enum // parameters for hash table
  255. {
  256. bucket_size = 4, // 0 < bucket_size
  257. min_buckets = 8
  258. };// min_buckets = 2 ^^ N, 0 < N
  259. size_t operator()(const Key& key) const
  260. {
  261. unsigned int h = 0;
  262. const char* s = constchar_cast(key);
  263. for (; *s; ++s)
  264. {
  265. h = 5 * h + *(unsigned char*)s;
  266. }
  267. return size_t(h);
  268. };
  269. };
  270. //////////////////////////////////////////////////////////////////////////
  271. //! Case sensitive string equality
  272. //////////////////////////////////////////////////////////////////////////
  273. template <class Key>
  274. class equality_string
  275. {
  276. public:
  277. bool operator()(const Key& key1, const Key& key2) const
  278. {
  279. return strcmp(constchar_cast(key1), constchar_cast(key2)) == 0;
  280. }
  281. };
  282. //////////////////////////////////////////////////////////////////////////
  283. //! Case insensitive string hasher
  284. //////////////////////////////////////////////////////////////////////////
  285. template <class Key>
  286. class hash_string_caseless
  287. {
  288. public:
  289. enum // parameters for hash table
  290. {
  291. bucket_size = 4, // 0 < bucket_size
  292. min_buckets = 8
  293. };// min_buckets = 2 ^^ N, 0 < N
  294. size_t operator()(const Key& key) const
  295. {
  296. unsigned int h = 0;
  297. const char* s = constchar_cast(key);
  298. for (; *s; ++s)
  299. {
  300. h = 5 * h + tolower(*(unsigned char*)s);
  301. }
  302. return size_t(h);
  303. };
  304. };
  305. //////////////////////////////////////////////////////////////////////////
  306. //! Case insensitive string comparer
  307. //////////////////////////////////////////////////////////////////////////
  308. template <class Key>
  309. class equality_string_caseless
  310. {
  311. public:
  312. bool operator()(const Key& key1, const Key& key2) const
  313. {
  314. return _stricmp(constchar_cast(key1), constchar_cast(key2)) == 0;
  315. }
  316. };
  317. template <class T>
  318. inline void reconstruct(T& t)
  319. {
  320. t.~T();
  321. new(&t)T;
  322. }
  323. template <typename T, typename A1>
  324. inline void reconstruct(T& t, const A1& a1)
  325. {
  326. t.~T();
  327. new (&t)T(a1);
  328. }
  329. template <typename T, typename A1, typename A2>
  330. inline void reconstruct(T& t, const A1& a1, const A2& a2)
  331. {
  332. t.~T();
  333. new (&t)T(a1, a2);
  334. }
  335. template <typename T, typename A1, typename A2, typename A3>
  336. inline void reconstruct(T& t, const A1& a1, const A2& a2, const A3& a3)
  337. {
  338. t.~T();
  339. new (&t)T(a1, a2, a3);
  340. }
  341. template <typename T, typename A1, typename A2, typename A3, typename A4>
  342. inline void reconstruct(T& t, const A1& a1, const A2& a2, const A3& a3, const A4& a4)
  343. {
  344. t.~T();
  345. new (&t)T(a1, a2, a3, a4);
  346. }
  347. template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5>
  348. inline void reconstruct(T& t, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5)
  349. {
  350. t.~T();
  351. new (&t)T(a1, a2, a3, a4, a5);
  352. }
  353. template <class T>
  354. inline void free_container(T& t)
  355. {
  356. reconstruct(t);
  357. }
  358. template <class T, class A>
  359. inline void free_container(std::deque<T, A>& t)
  360. {
  361. reconstruct(t);
  362. }
  363. template <class K, class D, class H, class A>
  364. inline void free_container(std__hash_map<K, D, H, A>& t)
  365. {
  366. reconstruct(t);
  367. }
  368. struct container_freer
  369. {
  370. template <typename T>
  371. void operator () (T& container) const
  372. {
  373. stl::free_container(container);
  374. }
  375. };
  376. }