EnumSet.h 6.1 KB

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