fbxhashmap.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. /****************************************************************************************
  2. Copyright (C) 2015 Autodesk, Inc.
  3. All rights reserved.
  4. Use of this software is subject to the terms of the Autodesk license agreement
  5. provided at the time of installation or download, or which otherwise accompanies
  6. this software in either electronic or hard copy form.
  7. ****************************************************************************************/
  8. //! \file fbxhashmap.h
  9. #ifndef _FBXSDK_CORE_BASE_HASHMAP_H_
  10. #define _FBXSDK_CORE_BASE_HASHMAP_H_
  11. #include <fbxsdk/fbxsdk_def.h>
  12. #include <fbxsdk/core/base/fbxarray.h>
  13. #include <fbxsdk/core/base/fbxmap.h>
  14. #include <fbxsdk/fbxsdk_nsbegin.h>
  15. template<class T> class FbxNoOpDestruct { public: static inline void DoIt(T&) {} };
  16. template<class T> class FbxPtrDestruct { public: static inline void DoIt(T& v) { FbxDelete(v); v = NULL; } };
  17. //True if equal, false otherwise
  18. template<class T> class FbxDefaultComparator{ public: static inline bool CompareIt( const T& t1, const T& t2 ) { return t1 == t2; } };
  19. /** \brief This object represents a standard hash map. You must provide the typename of KEY and VALUE as well
  20. as the typename of the class that contains the hash function to use to hash values. The hash class must
  21. overload operator() and be built like this.
  22. \code
  23. class SimpleHash
  24. {
  25. public:
  26. inline unsigned int operator() ( const int pKey ) const
  27. {
  28. return pKey;
  29. }
  30. };
  31. \endcode
  32. * \nosubgrouping
  33. */
  34. template< typename KEY, typename VALUE, typename HASH, class Destruct = FbxNoOpDestruct<VALUE>, class Comparator = FbxDefaultComparator<KEY> >
  35. class FbxHashMap
  36. {
  37. public:
  38. typedef KEY KeyType;
  39. typedef VALUE ValueType;
  40. typedef HASH HashFunctorType;
  41. private:
  42. class ListItem
  43. {
  44. public:
  45. ListItem* mNext;
  46. ValueType mValue;
  47. KeyType mKey;
  48. ListItem()
  49. :
  50. mNext(NULL)
  51. {
  52. }
  53. ~ListItem()
  54. {
  55. Destruct::DoIt(mValue);
  56. }
  57. };
  58. public:
  59. /**
  60. Iterate through every element in a hash map.
  61. */
  62. class Iterator
  63. {
  64. public:
  65. typedef ListItem ListItemType;
  66. typedef FbxPair< KeyType, ValueType > KeyValuePair;
  67. /**
  68. Copy constructor
  69. */
  70. Iterator( const Iterator& pOther )
  71. :
  72. mMap( pOther.mMap ),
  73. mBucketIndex( pOther.mBucketIndex ),
  74. mCurrentItem( pOther.mCurrentItem )
  75. {
  76. }
  77. /**
  78. Destructor
  79. */
  80. ~Iterator(){};
  81. /**
  82. Used to dereference an iterator and give it a behavior more similar to a pointer.
  83. \return The KeyValuePair currently referenced by the iterator
  84. */
  85. KeyValuePair operator*() const
  86. {
  87. KeyValuePair lItem;
  88. if( mCurrentItem )
  89. {
  90. lItem.mFirst = mCurrentItem->mKey;
  91. lItem.mSecond = mCurrentItem->mValue;
  92. return lItem;
  93. }
  94. FBX_ASSERT_NOW("Accessing out of bounds iterator");
  95. return lItem;
  96. }
  97. /**
  98. Advances the iterator to the next keyvaluepair in the hashmap. It does not wrap around so
  99. advancing after reaching the last element will not point back to the first one.
  100. */
  101. void Next()
  102. {
  103. if( !mCurrentItem )
  104. return;
  105. if( mCurrentItem->mNext )
  106. {
  107. mCurrentItem = mCurrentItem->mNext;
  108. return;
  109. }
  110. else
  111. {
  112. mBucketIndex++;
  113. for( ; mBucketIndex < mMap->mBuckets.GetCount(); ++mBucketIndex )
  114. {
  115. if( mMap->mBuckets[ mBucketIndex ] )
  116. {
  117. mCurrentItem = mMap->mBuckets[ mBucketIndex ];
  118. return;
  119. }
  120. }
  121. if( mBucketIndex >= mMap->mBuckets.GetCount() )
  122. {
  123. *this = mMap->End();
  124. return;
  125. }
  126. }
  127. }
  128. /**
  129. Check equivalence between two iterators. There are 3 conditions for equivalence between 2 iterators:
  130. 1) Item being referenced by the iterator must be equivalent
  131. 2) They must point at the same index
  132. 3) They must point on the same map
  133. \return true if both iterators are equal, false otherwise
  134. */
  135. bool operator==( const Iterator& pOther ) const
  136. {
  137. return mCurrentItem == pOther.mCurrentItem &&
  138. mBucketIndex == pOther.mBucketIndex &&
  139. mMap == pOther.mMap;
  140. }
  141. /**
  142. Check inequivalence between 2 iterators. Please see operator== for more information.
  143. \return true if both iterators are NOT equal, false if they are
  144. */
  145. bool operator!=( const Iterator& pOther ) const
  146. {
  147. return !(*this == pOther);
  148. }
  149. /**
  150. Assign the current iterator to the one on the right hand side of the operator. After assignment they will
  151. reference the same object, at the same index, in the same map.
  152. \return The new iterator
  153. */
  154. Iterator& operator=( const Iterator& pOther )
  155. {
  156. this->mBucketIndex = pOther.mBucketIndex;
  157. this->mMap = pOther.mMap;
  158. this->mCurrentItem = pOther.mCurrentItem;
  159. return *this;
  160. }
  161. private:
  162. const FbxHashMap* mMap;
  163. int mBucketIndex;
  164. ListItemType* mCurrentItem;
  165. Iterator(const FbxHashMap* pMap, int pBucketIndex, ListItemType* pCurrentItem)
  166. :
  167. mMap( pMap ),
  168. mBucketIndex(pBucketIndex),
  169. mCurrentItem(pCurrentItem)
  170. {
  171. }
  172. friend class FbxHashMap;
  173. };
  174. /**
  175. Construct a FbxHashMap with an user-defined maximum number of elements.
  176. \param pBucketSize Initial maximum number of elements.
  177. */
  178. FbxHashMap( int pBucketSize )
  179. {
  180. mBuckets.Resize( pBucketSize );
  181. }
  182. /**
  183. Construct a FbxHashMap with the default maximum number of elements (30)
  184. */
  185. FbxHashMap()
  186. {
  187. mBuckets.Resize(30);
  188. }
  189. /**
  190. Clear all elements in the hash map before destroying itself
  191. */
  192. ~FbxHashMap()
  193. {
  194. Clear();
  195. mBuckets.Clear();
  196. }
  197. /**
  198. Calls operator delete on all elements of the hashmap, de-allocating all memory and destroying them
  199. */
  200. void Clear()
  201. {
  202. for( int i = 0; i < mBuckets.GetCount(); ++i)
  203. {
  204. if( mBuckets[i] )
  205. {
  206. ListItem* lNext = mBuckets[i]->mNext;
  207. while( lNext )
  208. {
  209. ListItem* lNextNext = lNext->mNext;
  210. FbxDelete(lNext);
  211. lNext = lNextNext;
  212. }
  213. FbxDelete(mBuckets[i]);
  214. mBuckets[i] = NULL;
  215. }
  216. }
  217. }
  218. /**
  219. Find an element in the hashmap. If no element exist with the specified key, returns an iterator pointing on the
  220. end of the map (not an actual KeyValuePair).
  221. \param pKey The value of the key corresponding to the element
  222. \return An Iterator referencing that element
  223. */
  224. const Iterator Find( const KeyType& pKey ) const
  225. {
  226. unsigned int lIndex = mHashFunctor(pKey);
  227. lIndex = lIndex % mBuckets.GetCount();
  228. ListItem* lItem = mBuckets[lIndex];
  229. while( lItem )
  230. {
  231. if( Comparator::CompareIt( lItem->mKey, pKey ) )
  232. {
  233. Iterator lIt( this, lIndex, lItem );
  234. return lIt;
  235. }
  236. lItem = lItem->mNext;
  237. }
  238. return End();
  239. }
  240. /**
  241. Remove an element in the hashmap.
  242. \param pKey The key value of the element to remove
  243. \return The value of the element that was just deleted. If the element does not exist, a value created with its default constructor will be returned
  244. */
  245. VALUE Remove( const KEY& pKey )
  246. {
  247. unsigned int lIndex = mHashFunctor(pKey);
  248. lIndex = lIndex % mBuckets.GetCount();
  249. ListItem* lItem = mBuckets.GetAt(lIndex);
  250. ListItem* lLastItem = NULL;
  251. while( lItem )
  252. {
  253. if( lItem->mKey == pKey )
  254. {
  255. if( lLastItem )
  256. lLastItem->mNext = lItem->mNext;
  257. if( mBuckets.GetAt(lIndex) == lItem )
  258. mBuckets.SetAt(lIndex, lItem->mNext );
  259. VALUE lValue = lItem->mValue;
  260. FbxDelete(lItem);
  261. return lValue;
  262. }
  263. lLastItem = lItem;
  264. lItem = lItem->mNext;
  265. }
  266. return VALUE();
  267. }
  268. /** Add or retrieve a KeyValuePair from the Hashmap. If there is already an entry in the map for an element
  269. with key value specified in parameter, the value will be returned. Otherwise, a new entry will be created
  270. with this key value and the default value for ValueType will be returned. It can be modified using the
  271. assignment operator
  272. \param pKey The key for which to retrieve/add a value.
  273. \return Value of the element referenced by the key specified in parameter.
  274. */
  275. ValueType& operator[]( const KeyType& pKey )
  276. {
  277. unsigned int lIndex = 0;
  278. Iterator lIt = InternalFind( pKey, lIndex);
  279. if( lIt != End() )
  280. {
  281. return lIt.mCurrentItem->mValue;
  282. }
  283. lIndex = lIndex % mBuckets.GetCount();
  284. ListItem* lItem = FbxNew< ListItem >();
  285. lItem->mNext = NULL;
  286. lItem->mKey = pKey;
  287. if( !mBuckets.GetAt(lIndex) )
  288. {
  289. mBuckets.SetAt(lIndex, lItem);
  290. }
  291. else
  292. {
  293. lItem->mNext = mBuckets.GetAt(lIndex);
  294. mBuckets.SetAt(lIndex, lItem);
  295. }
  296. return lItem->mValue;
  297. }
  298. /** Returns an iterator pointing on the first non-null element in the map
  299. \return An iterator pointing on the first non-null element in the map.
  300. */
  301. Iterator Start() const
  302. {
  303. for( int i = 0; i < mBuckets.GetCount(); ++i )
  304. {
  305. if( mBuckets[i] )
  306. {
  307. Iterator lIt( this, i, mBuckets[i] );
  308. return lIt;
  309. }
  310. }
  311. return End();
  312. }
  313. /** Returns an iterator pointing on the last element in the map. This is not an actual KeyValuePair but
  314. * but an iterator pointing on a null element.
  315. \return Iterator pointing on a null value at the end of the map
  316. */
  317. Iterator End() const
  318. {
  319. Iterator lIt( this, 0, NULL );
  320. return lIt;
  321. }
  322. private:
  323. // Avoid calculating the hashvalue twice
  324. const Iterator InternalFind( const KeyType& pKey, unsigned int& pOutCalculatedIndex ) const
  325. {
  326. pOutCalculatedIndex = mHashFunctor(pKey);
  327. unsigned int lIndex = pOutCalculatedIndex % mBuckets.GetCount();
  328. ListItem* lItem = mBuckets[lIndex];
  329. while( lItem )
  330. {
  331. if( Comparator::CompareIt( lItem->mKey, pKey ) )
  332. {
  333. Iterator lIt( this, lIndex, lItem );
  334. return lIt;
  335. }
  336. lItem = lItem->mNext;
  337. }
  338. return End();
  339. }
  340. // not implemented yet!
  341. FbxHashMap( const FbxHashMap& pOther ) {};
  342. FbxArray<ListItem*> mBuckets;
  343. HashFunctorType mHashFunctor;
  344. friend class Iterator;
  345. };
  346. #include <fbxsdk/fbxsdk_nsend.h>
  347. #endif /* _FBXSDK_CORE_BASE_HASHMAP_H_ */