EnumSet.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* vim: set ts=8 sts=2 et sw=2 tw=80: */
  3. /* This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. /* A set abstraction for enumeration values. */
  7. #ifndef mozilla_EnumSet_h
  8. #define mozilla_EnumSet_h
  9. #include "mozilla/Assertions.h"
  10. #include "mozilla/Attributes.h"
  11. #include <initializer_list>
  12. #include <stdint.h>
  13. namespace mozilla {
  14. /**
  15. * EnumSet<T> is a set of values defined by an enumeration. It is implemented
  16. * using a 32 bit mask for each value so it will only work for enums with an int
  17. * representation less than 32. It works both for enum and enum class types.
  18. */
  19. template<typename T>
  20. class EnumSet
  21. {
  22. public:
  23. EnumSet()
  24. : mBitField(0)
  25. {
  26. initVersion();
  27. }
  28. MOZ_IMPLICIT EnumSet(T aEnum)
  29. : mBitField(bitFor(aEnum))
  30. { }
  31. EnumSet(T aEnum1, T aEnum2)
  32. : mBitField(bitFor(aEnum1) |
  33. bitFor(aEnum2))
  34. {
  35. initVersion();
  36. }
  37. EnumSet(T aEnum1, T aEnum2, T aEnum3)
  38. : mBitField(bitFor(aEnum1) |
  39. bitFor(aEnum2) |
  40. bitFor(aEnum3))
  41. {
  42. initVersion();
  43. }
  44. EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4)
  45. : mBitField(bitFor(aEnum1) |
  46. bitFor(aEnum2) |
  47. bitFor(aEnum3) |
  48. bitFor(aEnum4))
  49. {
  50. initVersion();
  51. }
  52. MOZ_IMPLICIT EnumSet(std::initializer_list<T> list)
  53. : mBitField(0)
  54. {
  55. for (auto value : list) {
  56. (*this) += value;
  57. }
  58. initVersion();
  59. }
  60. EnumSet(const EnumSet& aEnumSet)
  61. : mBitField(aEnumSet.mBitField)
  62. {
  63. initVersion();
  64. }
  65. /**
  66. * Add an element
  67. */
  68. void operator+=(T aEnum)
  69. {
  70. incVersion();
  71. mBitField |= bitFor(aEnum);
  72. }
  73. /**
  74. * Add an element
  75. */
  76. EnumSet<T> operator+(T aEnum) const
  77. {
  78. EnumSet<T> result(*this);
  79. result += aEnum;
  80. return result;
  81. }
  82. /**
  83. * Union
  84. */
  85. void operator+=(const EnumSet<T> aEnumSet)
  86. {
  87. incVersion();
  88. mBitField |= aEnumSet.mBitField;
  89. }
  90. /**
  91. * Union
  92. */
  93. EnumSet<T> operator+(const EnumSet<T> aEnumSet) const
  94. {
  95. EnumSet<T> result(*this);
  96. result += aEnumSet;
  97. return result;
  98. }
  99. /**
  100. * Remove an element
  101. */
  102. void operator-=(T aEnum)
  103. {
  104. incVersion();
  105. mBitField &= ~(bitFor(aEnum));
  106. }
  107. /**
  108. * Remove an element
  109. */
  110. EnumSet<T> operator-(T aEnum) const
  111. {
  112. EnumSet<T> result(*this);
  113. result -= aEnum;
  114. return result;
  115. }
  116. /**
  117. * Remove a set of elements
  118. */
  119. void operator-=(const EnumSet<T> aEnumSet)
  120. {
  121. incVersion();
  122. mBitField &= ~(aEnumSet.mBitField);
  123. }
  124. /**
  125. * Remove a set of elements
  126. */
  127. EnumSet<T> operator-(const EnumSet<T> aEnumSet) const
  128. {
  129. EnumSet<T> result(*this);
  130. result -= aEnumSet;
  131. return result;
  132. }
  133. /**
  134. * Clear
  135. */
  136. void clear()
  137. {
  138. incVersion();
  139. mBitField = 0;
  140. }
  141. /**
  142. * Intersection
  143. */
  144. void operator&=(const EnumSet<T> aEnumSet)
  145. {
  146. incVersion();
  147. mBitField &= aEnumSet.mBitField;
  148. }
  149. /**
  150. * Intersection
  151. */
  152. EnumSet<T> operator&(const EnumSet<T> aEnumSet) const
  153. {
  154. EnumSet<T> result(*this);
  155. result &= aEnumSet;
  156. return result;
  157. }
  158. /**
  159. * Equality
  160. */
  161. bool operator==(const EnumSet<T> aEnumSet) const
  162. {
  163. return mBitField == aEnumSet.mBitField;
  164. }
  165. /**
  166. * Test is an element is contained in the set.
  167. */
  168. bool contains(T aEnum) const
  169. {
  170. return mBitField & bitFor(aEnum);
  171. }
  172. /**
  173. * Return the number of elements in the set.
  174. */
  175. uint8_t size() const
  176. {
  177. uint8_t count = 0;
  178. for (uint32_t bitField = mBitField; bitField; bitField >>= 1) {
  179. if (bitField & 1) {
  180. count++;
  181. }
  182. }
  183. return count;
  184. }
  185. bool isEmpty() const
  186. {
  187. return mBitField == 0;
  188. }
  189. uint32_t serialize() const
  190. {
  191. return mBitField;
  192. }
  193. void deserialize(uint32_t aValue)
  194. {
  195. incVersion();
  196. mBitField = aValue;
  197. }
  198. class ConstIterator
  199. {
  200. const EnumSet<T>* mSet;
  201. uint32_t mPos;
  202. #ifdef DEBUG
  203. uint64_t mVersion;
  204. #endif
  205. void checkVersion() {
  206. // Check that the set has not been modified while being iterated.
  207. MOZ_ASSERT_IF(mSet, mSet->mVersion == mVersion);
  208. }
  209. public:
  210. ConstIterator(const EnumSet<T>& aSet, uint32_t aPos)
  211. : mSet(&aSet), mPos(aPos)
  212. {
  213. #ifdef DEBUG
  214. mVersion = mSet->mVersion;
  215. #endif
  216. MOZ_ASSERT(aPos <= kMaxBits);
  217. if (aPos != kMaxBits && !mSet->contains(T(mPos)))
  218. ++*this;
  219. }
  220. ConstIterator(const ConstIterator& aOther)
  221. : mSet(aOther.mSet), mPos(aOther.mPos)
  222. {
  223. #ifdef DEBUG
  224. mVersion = aOther.mVersion;
  225. checkVersion();
  226. #endif
  227. }
  228. ConstIterator(ConstIterator&& aOther)
  229. : mSet(aOther.mSet), mPos(aOther.mPos)
  230. {
  231. #ifdef DEBUG
  232. mVersion = aOther.mVersion;
  233. checkVersion();
  234. #endif
  235. aOther.mSet = nullptr;
  236. }
  237. ~ConstIterator() {
  238. checkVersion();
  239. }
  240. bool operator==(const ConstIterator& other) {
  241. MOZ_ASSERT(mSet == other.mSet);
  242. checkVersion();
  243. return mPos == other.mPos;
  244. }
  245. bool operator!=(const ConstIterator& other) {
  246. return !(*this == other);
  247. }
  248. T operator*() {
  249. MOZ_ASSERT(mSet);
  250. MOZ_ASSERT(mPos < kMaxBits);
  251. MOZ_ASSERT(mSet->contains(T(mPos)));
  252. checkVersion();
  253. return T(mPos);
  254. }
  255. ConstIterator& operator++() {
  256. MOZ_ASSERT(mSet);
  257. MOZ_ASSERT(mPos < kMaxBits);
  258. checkVersion();
  259. do {
  260. mPos++;
  261. } while (mPos < kMaxBits && !mSet->contains(T(mPos)));
  262. return *this;
  263. }
  264. };
  265. ConstIterator begin() const {
  266. return ConstIterator(*this, 0);
  267. }
  268. ConstIterator end() const {
  269. return ConstIterator(*this, kMaxBits);
  270. }
  271. private:
  272. static uint32_t bitFor(T aEnum)
  273. {
  274. uint32_t bitNumber = (uint32_t)aEnum;
  275. MOZ_ASSERT(bitNumber < kMaxBits);
  276. return 1U << bitNumber;
  277. }
  278. void initVersion() {
  279. #ifdef DEBUG
  280. mVersion = 0;
  281. #endif
  282. }
  283. void incVersion() {
  284. #ifdef DEBUG
  285. mVersion++;
  286. #endif
  287. }
  288. static const size_t kMaxBits = 32;
  289. uint32_t mBitField;
  290. #ifdef DEBUG
  291. uint64_t mVersion;
  292. #endif
  293. };
  294. } // namespace mozilla
  295. #endif /* mozilla_EnumSet_h_*/