enumbitset.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. #pragma once
  2. #include <util/ysaveload.h>
  3. #include <util/generic/bitmap.h>
  4. #include <util/generic/serialized_enum.h>
  5. #include <util/generic/yexception.h>
  6. #include <util/string/cast.h>
  7. #include <util/string/printf.h>
  8. #include <util/system/yassert.h>
  9. // Stack memory bitmask for TEnum values [begin, end).
  10. // @end value is not included in the mask and is not necessarily defined as enum value.
  11. // For example: enum EType { A, B, C } ==> TEnumBitSet<EType, A, C + 1>
  12. template <typename TEnum, int mbegin, int mend>
  13. class TEnumBitSet: private TBitMap<mend - mbegin> {
  14. public:
  15. static const int BeginIndex = mbegin;
  16. static const int EndIndex = mend;
  17. static const size_t BitsetSize = EndIndex - BeginIndex;
  18. typedef TBitMap<BitsetSize> TParent;
  19. typedef TEnumBitSet<TEnum, mbegin, mend> TThis;
  20. TEnumBitSet()
  21. : TParent(0)
  22. {
  23. }
  24. explicit TEnumBitSet(const TParent& p)
  25. : TParent(p)
  26. {
  27. }
  28. void Init(TEnum c) {
  29. Set(c);
  30. }
  31. template <class... R>
  32. void Init(TEnum c1, TEnum c2, R... r) {
  33. Set(c1);
  34. Init(c2, r...);
  35. }
  36. explicit TEnumBitSet(TEnum c) {
  37. Init(c);
  38. }
  39. template <class... R>
  40. TEnumBitSet(TEnum c1, TEnum c2, R... r) {
  41. Init(c1, c2, r...);
  42. }
  43. template <class TIt>
  44. TEnumBitSet(const TIt& begin_, const TIt& end_) {
  45. for (TIt p = begin_; p != end_; ++p)
  46. Set(*p);
  47. }
  48. static bool IsValid(TEnum c) {
  49. return int(c) >= BeginIndex && int(c) < EndIndex;
  50. }
  51. bool Test(TEnum c) const {
  52. return TParent::Test(Pos(c));
  53. }
  54. TThis& Flip(TEnum c) {
  55. TParent::Flip(Pos(c));
  56. return *this;
  57. }
  58. TThis& Flip() {
  59. TParent::Flip();
  60. return *this;
  61. }
  62. TThis& Reset(TEnum c) {
  63. TParent::Reset(Pos(c));
  64. return *this;
  65. }
  66. TThis& Reset() {
  67. TParent::Clear();
  68. return *this;
  69. }
  70. TThis& Set(TEnum c) {
  71. TParent::Set(Pos(c));
  72. return *this;
  73. }
  74. TThis& Set(TEnum c, bool val) {
  75. if (val)
  76. Set(c);
  77. else
  78. Reset(c);
  79. return *this;
  80. }
  81. bool SafeTest(TEnum c) const {
  82. if (IsValid(c))
  83. return Test(c);
  84. return false;
  85. }
  86. TThis& SafeFlip(TEnum c) {
  87. if (IsValid(c))
  88. return Flip(c);
  89. return *this;
  90. }
  91. TThis& SafeReset(TEnum c) {
  92. if (IsValid(c))
  93. return Reset(c);
  94. return *this;
  95. }
  96. TThis& SafeSet(TEnum c) {
  97. if (IsValid(c))
  98. return Set(c);
  99. return *this;
  100. }
  101. TThis& SafeSet(TEnum c, bool val) {
  102. if (IsValid(c))
  103. return Set(c, val);
  104. return *this;
  105. }
  106. static TThis SafeConstruct(TEnum c) {
  107. TThis ret;
  108. ret.SafeSet(c);
  109. return ret;
  110. }
  111. bool operator<(const TThis& right) const {
  112. Y_ASSERT(this->GetChunkCount() == right.GetChunkCount());
  113. for (size_t i = 0; i < this->GetChunkCount(); ++i) {
  114. if (this->GetChunks()[i] < right.GetChunks()[i])
  115. return true;
  116. else if (this->GetChunks()[i] > right.GetChunks()[i])
  117. return false;
  118. }
  119. return false;
  120. }
  121. bool operator!=(const TThis& right) const {
  122. return !(TParent::operator==(right));
  123. }
  124. bool operator==(const TThis& right) const {
  125. return TParent::operator==(right);
  126. }
  127. TThis& operator&=(const TThis& right) {
  128. TParent::operator&=(right);
  129. return *this;
  130. }
  131. TThis& operator|=(const TThis& right) {
  132. TParent::operator|=(right);
  133. return *this;
  134. }
  135. TThis& operator^=(const TThis& right) {
  136. TParent::operator^=(right);
  137. return *this;
  138. }
  139. TThis operator~() const {
  140. TThis r = *this;
  141. r.Flip();
  142. return r;
  143. }
  144. TThis operator|(const TThis& right) const {
  145. TThis ret = *this;
  146. ret |= right;
  147. return ret;
  148. }
  149. TThis operator&(const TThis& right) const {
  150. TThis ret = *this;
  151. ret &= right;
  152. return ret;
  153. }
  154. TThis operator^(const TThis& right) const {
  155. TThis ret = *this;
  156. ret ^= right;
  157. return ret;
  158. }
  159. TThis& operator&=(const TEnum c) {
  160. return TThis::operator&=(TThis(c));
  161. }
  162. TThis& operator|=(const TEnum c) {
  163. return TThis::operator|=(TThis(c));
  164. }
  165. TThis& operator^=(const TEnum c) {
  166. return TThis::operator^=(TThis(c));
  167. }
  168. TThis operator&(const TEnum c) const {
  169. return TThis::operator&(TThis(c));
  170. }
  171. TThis operator|(const TEnum c) const {
  172. return TThis::operator|(TThis(c));
  173. }
  174. TThis operator^(const TEnum c) const {
  175. return TThis::operator^(TThis(c));
  176. }
  177. auto operator[] (TEnum e) {
  178. return TParent::operator[](this->Pos(e));
  179. }
  180. auto operator[] (TEnum e) const {
  181. return TParent::operator[](this->Pos(e));
  182. }
  183. using TParent::Count;
  184. using TParent::Empty;
  185. explicit operator bool() const {
  186. return !Empty();
  187. }
  188. void Swap(TThis& bitmap) {
  189. TParent::Swap(bitmap);
  190. }
  191. size_t GetHash() const {
  192. return this->Hash();
  193. }
  194. bool HasAny(const TThis& mask) const {
  195. return TParent::HasAny(mask);
  196. }
  197. template <class... R>
  198. bool HasAny(TEnum c1, R... r) const {
  199. return Test(c1) || HasAny(r...);
  200. }
  201. bool HasAll(const TThis& mask) const {
  202. return TParent::HasAll(mask);
  203. }
  204. template <class... R>
  205. bool HasAll(TEnum c1, R... r) const {
  206. return Test(c1) && HasAll(r...);
  207. }
  208. //serialization to/from stream
  209. void Save(IOutputStream* buffer) const {
  210. ::Save(buffer, (ui32)Count());
  211. for (TEnum bit : *this) {
  212. ::Save(buffer, (ui32)bit);
  213. }
  214. }
  215. void Load(IInputStream* buffer) {
  216. Reset();
  217. ui32 sz = 0;
  218. ::Load(buffer, sz);
  219. for (ui32 t = 0; t < sz; t++) {
  220. ui32 bit = 0;
  221. ::Load(buffer, bit);
  222. Set((TEnum)bit);
  223. }
  224. }
  225. ui64 Low() const {
  226. ui64 t = 0;
  227. this->Export(0, t);
  228. return t;
  229. }
  230. TString ToString() const {
  231. static_assert(sizeof(typename TParent::TChunk) <= sizeof(ui64), "expect sizeof(typename TParent::TChunk) <= sizeof(ui64)");
  232. static const size_t chunkSize = sizeof(typename TParent::TChunk) * 8;
  233. static const size_t numDig = chunkSize / 4;
  234. static const TString templ = Sprintf("%%0%lulX", numDig);
  235. static const size_t numOfChunks = (BitsetSize + chunkSize - 1) / chunkSize;
  236. TString ret;
  237. for (int pos = numOfChunks * chunkSize; pos >= 0; pos -= chunkSize) {
  238. ui64 t = 0;
  239. this->Export(pos, t);
  240. ret += Sprintf(templ.data(), t);
  241. }
  242. size_t n = 0;
  243. while (n + 1 < ret.length() && ret[n] == '0')
  244. ++n;
  245. ret.remove(0, n);
  246. return ret;
  247. }
  248. void FromString(TStringBuf s) {
  249. static const size_t chunkSize = sizeof(typename TParent::TChunk) * 8;
  250. static const size_t numDig = chunkSize / 4;
  251. static const size_t highChunkBits = (BitsetSize + chunkSize - 1) % chunkSize + 1;
  252. static const typename TParent::TChunk highChunkBitsMask = (typename TParent::TChunk(1) << highChunkBits) - 1;
  253. Reset();
  254. for (size_t prev = s.length(), n = s.length() - numDig, pos = 0; prev; n -= numDig, pos += chunkSize) {
  255. if (pos >= BitsetSize)
  256. ythrow yexception() << "too many digits";
  257. if (n > prev)
  258. n = 0;
  259. typename TParent::TChunk t = IntFromString<typename TParent::TChunk, 16, TStringBuf>(s.substr(n, prev - n));
  260. if (BitsetSize < pos + chunkSize && t > highChunkBitsMask)
  261. ythrow yexception() << "digit is too big";
  262. this->Or(TParent(t), pos);
  263. prev = n;
  264. }
  265. }
  266. // TODO: Get rid of exceptions at all
  267. bool TryFromString(TStringBuf s) {
  268. try {
  269. FromString(s);
  270. } catch (...) {
  271. Reset();
  272. return false;
  273. }
  274. return true;
  275. }
  276. bool any() const { // obsolete
  277. return !Empty();
  278. }
  279. bool none() const { // obsolete
  280. return Empty();
  281. }
  282. size_t count() const { // obsolete
  283. return Count();
  284. }
  285. class TIterator {
  286. public:
  287. TIterator(TEnum value, const TThis* bitmap) noexcept
  288. : Value(static_cast<int>(value))
  289. , BitMap(bitmap)
  290. {
  291. }
  292. TIterator(const TThis* bitmap) noexcept
  293. : Value(EndIndex)
  294. , BitMap(bitmap)
  295. {
  296. }
  297. TEnum operator*() const noexcept {
  298. Y_ASSERT(Value < EndIndex);
  299. return static_cast<TEnum>(Value);
  300. }
  301. bool operator!=(const TIterator& other) const noexcept {
  302. return Value != other.Value;
  303. }
  304. TIterator& operator++() noexcept {
  305. Y_ASSERT(Value < EndIndex);
  306. TEnum res;
  307. if (BitMap->FindNext(static_cast<TEnum>(Value), res)) {
  308. Value = static_cast<int>(res);
  309. } else {
  310. Value = EndIndex;
  311. }
  312. return *this;
  313. }
  314. private:
  315. int Value;
  316. const TThis* BitMap;
  317. };
  318. TIterator begin() const {
  319. TEnum res;
  320. return FindFirst(res) ? TIterator(res, this) : TIterator(this);
  321. }
  322. TIterator end() const {
  323. return TIterator(this);
  324. }
  325. private:
  326. static size_t Pos(TEnum c) {
  327. Y_ASSERT(IsValid(c));
  328. return static_cast<size_t>(int(c) - BeginIndex);
  329. }
  330. bool HasAny(TEnum c) const {
  331. return Test(c);
  332. }
  333. bool HasAll(TEnum c) const {
  334. return Test(c);
  335. }
  336. bool FindFirst(TEnum& result) const {
  337. // finds first set item in bitset (or End if bitset is empty)
  338. const int index = int(this->FirstNonZeroBit()) + BeginIndex;
  339. if (index < EndIndex) {
  340. result = static_cast<TEnum>(index);
  341. return true;
  342. }
  343. return false;
  344. }
  345. bool FindNext(TEnum current, TEnum& result) const {
  346. // finds first set item in bitset (or End if bitset is empty)
  347. const int index = int(this->NextNonZeroBit(int(current) - BeginIndex)) + BeginIndex;
  348. if (index < EndIndex) {
  349. result = static_cast<TEnum>(index);
  350. return true;
  351. }
  352. return false;
  353. }
  354. };
  355. template <typename TEnum, TEnum mbegin, int mend>
  356. class TSfEnumBitSet: public TEnumBitSet<TEnum, mbegin, mend> {
  357. public:
  358. typedef TEnumBitSet<TEnum, mbegin, mend> TParent;
  359. TSfEnumBitSet()
  360. : TParent()
  361. {
  362. }
  363. TSfEnumBitSet(const TParent& p)
  364. : TParent(p)
  365. {
  366. }
  367. //! unsafe initialization from ui64, value must be shifted according to TParent::Begin
  368. explicit TSfEnumBitSet(ui64 val)
  369. : TParent(typename TParent::TParent(val))
  370. {
  371. //static_assert(TParent::BitsetSize <= 64, "expect TParent::BitsetSize <= 64");
  372. }
  373. void Init(TEnum c) {
  374. this->SafeSet(c);
  375. }
  376. template <class... R>
  377. void Init(TEnum c1, TEnum c2, R... r) {
  378. this->SafeSet(c1);
  379. Init(c2, r...);
  380. }
  381. TSfEnumBitSet(TEnum c) {
  382. Init(c);
  383. }
  384. template <class... R>
  385. TSfEnumBitSet(TEnum c1, TEnum c2, R... r) {
  386. Init(c1, c2, r...);
  387. }
  388. static TSfEnumBitSet GetFromString(const TString& s) {
  389. TSfEnumBitSet ebs;
  390. ebs.FromString(s);
  391. return ebs;
  392. }
  393. static TSfEnumBitSet TryGetFromString(const TString& s) {
  394. TSfEnumBitSet ebs;
  395. ebs.TryFromString(s);
  396. return ebs;
  397. }
  398. };
  399. /* For Enums with GENERATE_ENUM_SERIALIZATION_WITH_HEADER */
  400. template <typename TEnum>
  401. class TGeneratedEnumBitSet : public TEnumBitSet<TEnum, 0, GetEnumItemsCount<TEnum>()> {
  402. public:
  403. using TParent = TEnumBitSet<TEnum, 0, GetEnumItemsCount<TEnum>()>;
  404. TGeneratedEnumBitSet()
  405. : TParent()
  406. {
  407. }
  408. explicit TGeneratedEnumBitSet(const TParent& p)
  409. : TParent(p)
  410. {
  411. }
  412. explicit TGeneratedEnumBitSet(TEnum c1)
  413. : TParent(c1)
  414. {
  415. }
  416. template <class... R>
  417. TGeneratedEnumBitSet(TEnum c1, TEnum c2, R... r)
  418. : TParent(c1, c2, r...)
  419. {
  420. }
  421. };