jset.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "jlib.hpp"
  14. #include "jset.hpp"
  15. #include "jmutex.hpp"
  16. #include "jexcept.hpp"
  17. //-----------------------------------------------------------------------
  18. // NB: The CBitSet*Helper's are primarily avoid the need for virtuals in the implementations
  19. class CBitSetArrayHelper
  20. {
  21. protected:
  22. ArrayOf<bits_t> bits;
  23. inline bits_t getBits(unsigned i) const { return bits.item(i); }
  24. inline void setBits(unsigned i, bits_t m)
  25. {
  26. bits.replace(m, i);
  27. }
  28. inline void addBitSet(bits_t m)
  29. {
  30. bits.append(m);
  31. }
  32. inline unsigned getWidth() const { return bits.ordinality(); }
  33. };
  34. class CBitSetMemoryHelper
  35. {
  36. protected:
  37. bits_t *mem;
  38. unsigned bitSetUnits;
  39. MemoryBuffer mb; // Used if mem not provided, also implies expansion allowed
  40. bool fixedMemory;
  41. CBitSetMemoryHelper()
  42. {
  43. fixedMemory = false;
  44. bitSetUnits = 0;
  45. mem = NULL;
  46. }
  47. inline bits_t getBits(unsigned i) const { return mem[i]; }
  48. inline void setBits(unsigned i, bits_t m) { mem[i] = m; }
  49. inline void addBitSet(bits_t m)
  50. {
  51. if (fixedMemory)
  52. throw MakeStringException(-1, "CBitSet with fixed mem cannot expand");
  53. mb.append(m);
  54. mem = (bits_t *)mb.bufferBase();
  55. ++bitSetUnits;
  56. }
  57. inline unsigned getWidth() const { return bitSetUnits; }
  58. };
  59. template <class BITSETHELPER>
  60. class CBitSetBase : public BITSETHELPER, public CSimpleInterfaceOf<IBitSet>
  61. {
  62. protected:
  63. typedef BITSETHELPER PARENT;
  64. using PARENT::getWidth;
  65. using PARENT::getBits;
  66. using PARENT::setBits;
  67. using PARENT::addBitSet;
  68. unsigned _scan(unsigned from, bool tst, bool scninv)
  69. {
  70. bits_t noMatchMask=tst?0:(bits_t)-1;
  71. unsigned j=from%BitsPerItem;
  72. // returns index of first = val >= from
  73. unsigned n=getWidth();
  74. unsigned i = from/BitsPerItem;
  75. if (j != 0 && i < n)
  76. {
  77. bits_t m = getBits(i);
  78. if (m!=noMatchMask)
  79. {
  80. //Evaluate (testMask = tst ? m : ~m); without using a conditional.
  81. //After this bits will be set wherever we want a match
  82. bits_t testMask = m ^ noMatchMask;
  83. //Clear all the bottom bits
  84. bits_t mask = (((bits_t)1)<<j)-1;
  85. testMask &= ~mask;
  86. //May possibly be empty now ignored bits are removed - if so continue main loop
  87. if (testMask != 0)
  88. {
  89. //Guaranteed a match at this point
  90. //Returns one the index of the least significant 1-bit of testMask
  91. //(testMask != 0) since that has been checked above (noMatchMask == 0)
  92. unsigned pos = countTrailingUnsetBits(testMask);
  93. if (scninv)
  94. {
  95. bits_t t = ((bits_t)1)<<pos;
  96. m ^= t;
  97. setBits(i, m);
  98. }
  99. return i*BitsPerItem+pos;
  100. }
  101. }
  102. j = 0;
  103. i++;
  104. }
  105. for (;i<n;i++)
  106. {
  107. bits_t m = getBits(i);
  108. if (m!=noMatchMask)
  109. {
  110. //Evaluate (testMask = tst ? m : ~m); without using a conditional.
  111. //After this bits will be set wherever we want a match
  112. bits_t testMask = m ^ noMatchMask;
  113. //Guaranteed a match at this point
  114. //Returns one the index of the least significant 1-bit of testMask
  115. //(testMask != 0) since that has been checked above (noMatchMask == 0)
  116. unsigned pos = countTrailingUnsetBits(testMask);
  117. if (scninv)
  118. {
  119. bits_t t = ((bits_t)1)<<pos;
  120. m ^= t;
  121. setBits(i, m);
  122. }
  123. return i*BitsPerItem+pos;
  124. }
  125. }
  126. if (tst)
  127. return (unsigned)-1;
  128. unsigned ret = n*BitsPerItem;
  129. if (n*BitsPerItem<from)
  130. ret = from;
  131. if (scninv)
  132. set(ret,true);
  133. return ret;
  134. }
  135. void _incl(unsigned lo, unsigned hi, bool val)
  136. {
  137. if (hi<lo)
  138. return;
  139. unsigned j=lo%BitsPerItem;
  140. unsigned nb=(hi-lo)+1;
  141. unsigned n=getWidth();
  142. unsigned i=lo/BitsPerItem;
  143. if (n<=i)
  144. {
  145. if (!val)
  146. return;
  147. while (n < i)
  148. {
  149. addBitSet(0);
  150. ++n;
  151. }
  152. if (j>0)
  153. {
  154. bits_t m = 0;
  155. bits_t t = ((bits_t)1)<<j;
  156. for (;j<BitsPerItem;j++)
  157. {
  158. m |= t;
  159. if (--nb==0)
  160. break;
  161. t <<= 1;
  162. }
  163. addBitSet(m);
  164. }
  165. if (nb==0)
  166. return;
  167. j = 0;
  168. }
  169. else
  170. {
  171. for (;i<n;i++)
  172. {
  173. bits_t m;
  174. if ((nb>=BitsPerItem)&&(j==0))
  175. {
  176. if (val)
  177. m = (bits_t)-1;
  178. else
  179. m = 0;
  180. nb -= BitsPerItem;
  181. }
  182. else
  183. {
  184. m = getBits(i);
  185. bits_t t = ((bits_t)1)<<j;
  186. for (;j<BitsPerItem;j++)
  187. {
  188. if (val)
  189. m |= t;
  190. else
  191. m &= ~t;
  192. if (--nb==0)
  193. break;
  194. t <<= 1;
  195. }
  196. }
  197. setBits(i, m);
  198. if (nb==0)
  199. return;
  200. j = 0;
  201. }
  202. }
  203. if (val)
  204. {
  205. while (nb>=BitsPerItem)
  206. {
  207. addBitSet((bits_t)-1);
  208. nb -= BitsPerItem;
  209. }
  210. if (nb>0)
  211. {
  212. bits_t m=0;
  213. bits_t t = ((bits_t)1)<<j;
  214. for (;j<BitsPerItem;j++)
  215. {
  216. m |= t;
  217. if (--nb==0)
  218. break;
  219. t <<= 1;
  220. }
  221. addBitSet(m);
  222. }
  223. }
  224. }
  225. public:
  226. // IBitSet impl.
  227. virtual void set(unsigned n, bool val)
  228. {
  229. bits_t t=((bits_t)1)<<(n%BitsPerItem);
  230. unsigned i = n/BitsPerItem;
  231. if (i>=getWidth())
  232. {
  233. if (!val)
  234. return; // don't bother
  235. while (i>getWidth())
  236. addBitSet(0);
  237. addBitSet(t);
  238. }
  239. else
  240. {
  241. bits_t m = getBits(i);
  242. if (val)
  243. m |= t;
  244. else
  245. m &= ~t;
  246. setBits(i, m);
  247. }
  248. }
  249. virtual bool invert(unsigned n)
  250. {
  251. bits_t t=((bits_t)1)<<(n%BitsPerItem);
  252. unsigned i=n/BitsPerItem;
  253. bool ret;
  254. if (i>=getWidth())
  255. {
  256. while (i>getWidth())
  257. addBitSet(0);
  258. addBitSet(t);
  259. ret = true;
  260. }
  261. else
  262. {
  263. bits_t m = getBits(i);
  264. ret = 0 == (m&t);
  265. if (ret)
  266. m |= t;
  267. else
  268. m &= ~t;
  269. setBits(i, m);
  270. }
  271. return ret;
  272. }
  273. virtual bool test(unsigned n)
  274. {
  275. bits_t t=((bits_t)1)<<(n%BitsPerItem);
  276. unsigned i=n/BitsPerItem;
  277. if (i<getWidth())
  278. {
  279. bits_t m = getBits(i);
  280. if (m&t)
  281. return true;
  282. }
  283. return false;
  284. }
  285. virtual bool testSet(unsigned n, bool val)
  286. {
  287. bits_t t=((bits_t)1)<<(n%BitsPerItem);
  288. unsigned i=n/BitsPerItem;
  289. if (i>=getWidth())
  290. {
  291. if (val)
  292. {
  293. while (i>getWidth())
  294. addBitSet(0);
  295. addBitSet(t);
  296. }
  297. return false;
  298. }
  299. else
  300. {
  301. bits_t m = getBits(i);
  302. if (m&t)
  303. {
  304. if (!val)
  305. setBits(i, m & ~t);
  306. return true;
  307. }
  308. else
  309. {
  310. if (val)
  311. setBits(i, m | t);
  312. return false;
  313. }
  314. }
  315. }
  316. virtual unsigned scan(unsigned from,bool tst)
  317. {
  318. return _scan(from,tst,false);
  319. }
  320. virtual unsigned scanInvert(unsigned from,bool tst) // like scan but inverts bit as well
  321. {
  322. return _scan(from,tst,true);
  323. }
  324. virtual void incl(unsigned lo, unsigned hi)
  325. {
  326. _incl(lo,hi,true);
  327. }
  328. virtual void excl(unsigned lo, unsigned hi)
  329. {
  330. _incl(lo,hi,false);
  331. }
  332. };
  333. size32_t getBitSetMemoryRequirement(unsigned numBits)
  334. {
  335. unsigned bitSetUnits = (numBits + (BitsPerItem-1)) / BitsPerItem;
  336. return bitSetUnits * sizeof(bits_t);
  337. }
  338. // Simple BitSet // 0 based all, intermediate items exist, operations threadsafe and atomic
  339. class CBitSetThreadSafe : public CBitSetBase<CBitSetArrayHelper>
  340. {
  341. typedef CBitSetBase<CBitSetArrayHelper> PARENT;
  342. mutable CriticalSection crit;
  343. void deserialize(MemoryBuffer &buffer)
  344. {
  345. CriticalBlock block(crit);
  346. bits.kill();
  347. unsigned count;
  348. buffer.read(count);
  349. if (count)
  350. {
  351. bits.ensure(count);
  352. while (count--)
  353. {
  354. bits_t b;
  355. buffer.read(b);
  356. bits.append(b);
  357. }
  358. }
  359. }
  360. public:
  361. CBitSetThreadSafe()
  362. {
  363. }
  364. CBitSetThreadSafe(MemoryBuffer &buffer)
  365. {
  366. deserialize(buffer);
  367. }
  368. // IBitSet overloads
  369. virtual void set(unsigned n, bool val)
  370. {
  371. CriticalBlock block(crit);
  372. PARENT::set(n, val);
  373. }
  374. virtual bool invert(unsigned n)
  375. {
  376. CriticalBlock block(crit);
  377. return PARENT::invert(n);
  378. }
  379. virtual bool test(unsigned n)
  380. {
  381. CriticalBlock block(crit);
  382. return PARENT::test(n);
  383. }
  384. virtual bool testSet(unsigned n, bool val)
  385. {
  386. CriticalBlock block(crit);
  387. return PARENT::testSet(n, val);
  388. }
  389. virtual unsigned scan(unsigned from, bool tst)
  390. {
  391. CriticalBlock block(crit);
  392. return _scan(from,tst,false);
  393. }
  394. virtual unsigned scanInvert(unsigned from, bool tst) // like scan but inverts bit as well
  395. {
  396. CriticalBlock block(crit);
  397. return _scan(from,tst,true);
  398. }
  399. virtual void incl(unsigned lo, unsigned hi)
  400. {
  401. CriticalBlock block(crit);
  402. _incl(lo,hi,true);
  403. }
  404. virtual void excl(unsigned lo, unsigned hi)
  405. {
  406. CriticalBlock block(crit);
  407. _incl(lo,hi,false);
  408. }
  409. virtual void reset()
  410. {
  411. CriticalBlock block(crit);
  412. bits.kill();
  413. }
  414. virtual void serialize(MemoryBuffer &buffer) const
  415. {
  416. CriticalBlock block(crit);
  417. buffer.append(bits.ordinality());
  418. ForEachItemIn(b, bits)
  419. buffer.append(bits.item(b));
  420. }
  421. };
  422. extern jlib_decl IBitSet *createThreadSafeBitSet()
  423. {
  424. return new CBitSetThreadSafe();
  425. }
  426. class CBitSet : public CBitSetBase<CBitSetMemoryHelper>
  427. {
  428. void deserialize(MemoryBuffer &buffer)
  429. {
  430. unsigned count;
  431. buffer.read(count);
  432. if (count)
  433. {
  434. unsigned bitSets = count/BitsPerItem;
  435. bitSetUnits = bitSets;
  436. mem = (bits_t *)mb.reserveTruncate(bitSets*sizeof(bits_t));
  437. }
  438. else
  439. {
  440. bitSetUnits = 0;
  441. mem = NULL;
  442. }
  443. fixedMemory = false;
  444. }
  445. public:
  446. CBitSet()
  447. {
  448. // In this form, bitSetUnits and mem will be updated when addBitSet expands mb
  449. }
  450. CBitSet(size32_t memSz, const void *_mem, bool reset)
  451. {
  452. bitSetUnits = memSz*sizeof(byte) / sizeof(bits_t);
  453. mem = (bits_t *)_mem;
  454. if (reset)
  455. memset(mem, 0, bitSetUnits*sizeof(bits_t));
  456. fixedMemory = true;
  457. }
  458. CBitSet(unsigned initialBits)
  459. {
  460. size32_t memRequired = getBitSetMemoryRequirement(initialBits);
  461. mb.appendBytes(0, memRequired);
  462. mem = (bits_t *)mb.bufferBase();
  463. bitSetUnits = memRequired/sizeof(bits_t);
  464. fixedMemory = false;
  465. }
  466. CBitSet(MemoryBuffer &buffer)
  467. {
  468. deserialize(buffer);
  469. }
  470. virtual void reset()
  471. {
  472. memset(mem, 0, sizeof(bits_t)*bitSetUnits);
  473. }
  474. virtual void serialize(MemoryBuffer &buffer) const
  475. {
  476. buffer.append((unsigned)(BitsPerItem*bitSetUnits));
  477. buffer.append(bitSetUnits*sizeof(bits_t), mem);
  478. }
  479. };
  480. extern jlib_decl IBitSet *createBitSet(unsigned maxBits, const void *mem, bool reset)
  481. {
  482. return new CBitSet(maxBits, mem, reset);
  483. }
  484. extern jlib_decl IBitSet *createBitSet(unsigned initialBits)
  485. {
  486. return new CBitSet(initialBits);
  487. }
  488. extern jlib_decl IBitSet *createBitSet()
  489. {
  490. return new CBitSet();
  491. }
  492. // NB: Doubt you'd want to interchange, but serialization formats are compatible
  493. extern jlib_decl IBitSet *deserializeThreadSafeBitSet(MemoryBuffer &mb)
  494. {
  495. return new CBitSetThreadSafe(mb);
  496. }
  497. extern jlib_decl IBitSet *deserializeBitSet(MemoryBuffer &mb)
  498. {
  499. return new CBitSet(mb);
  500. }