jset.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  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;
  75. for (i=from/BitsPerItem;i<n;i++)
  76. {
  77. bits_t m = getBits(i);
  78. if (m!=noMatchMask)
  79. {
  80. #if defined(__GNUC__)
  81. //Use the __builtin_ffs instead of a loop to find the first bit set/cleared
  82. bits_t testMask = m;
  83. if (j != 0)
  84. {
  85. //Set all the bottom bits to the value we're not searching for
  86. bits_t mask = (((bits_t)1)<<j)-1;
  87. if (tst)
  88. testMask &= ~mask;
  89. else
  90. testMask |= mask;
  91. //May possibly match exactly - if so continue main loop
  92. if (testMask==noMatchMask)
  93. {
  94. j = 0;
  95. continue;
  96. }
  97. }
  98. //Guaranteed a match at this point
  99. if (tst)
  100. {
  101. //Returns one plus the index of the least significant 1-bit of testMask
  102. //(testMask != 0) since that has been checked above (noMatchMask == 0)
  103. unsigned pos = __builtin_ffs(testMask)-1;
  104. if (scninv)
  105. {
  106. bits_t t = ((bits_t)1)<<pos;
  107. m &= ~t;
  108. setBits(i, m);
  109. }
  110. return i*BitsPerItem+pos;
  111. }
  112. else
  113. {
  114. //Same as above but invert the bitmask
  115. unsigned pos = __builtin_ffs(~testMask)-1;
  116. if (scninv)
  117. {
  118. bits_t t = ((bits_t)1)<<pos;
  119. m |= t;
  120. setBits(i, m);
  121. }
  122. return i*BitsPerItem+pos;
  123. }
  124. #else
  125. bits_t t = ((bits_t)1)<<j;
  126. for (;j<BitsPerItem;j++)
  127. {
  128. if (t&m)
  129. {
  130. if (tst)
  131. {
  132. if (scninv)
  133. {
  134. m &= ~t;
  135. setBits(i, m);
  136. }
  137. return i*BitsPerItem+j;
  138. }
  139. }
  140. else
  141. {
  142. if (!tst)
  143. {
  144. if (scninv)
  145. {
  146. m |= t;
  147. setBitSet(i, m);
  148. }
  149. return i*BitsPerItem+j;
  150. }
  151. }
  152. t <<= 1;
  153. }
  154. #endif
  155. }
  156. j = 0;
  157. }
  158. if (tst)
  159. return (unsigned)-1;
  160. unsigned ret = n*BitsPerItem;
  161. if (n*BitsPerItem<from)
  162. ret = from;
  163. if (scninv)
  164. set(ret,true);
  165. return ret;
  166. }
  167. void _incl(unsigned lo, unsigned hi, bool val)
  168. {
  169. if (hi<lo)
  170. return;
  171. unsigned j=lo%BitsPerItem;
  172. unsigned nb=(hi-lo)+1;
  173. unsigned n=getWidth();
  174. unsigned i=lo/BitsPerItem;
  175. if (n<=i)
  176. {
  177. if (!val)
  178. return;
  179. while (n < i)
  180. {
  181. addBitSet(0);
  182. ++n;
  183. }
  184. if (j>0)
  185. {
  186. bits_t m = 0;
  187. bits_t t = ((bits_t)1)<<j;
  188. for (;j<BitsPerItem;j++)
  189. {
  190. m |= t;
  191. if (--nb==0)
  192. break;
  193. t <<= 1;
  194. }
  195. addBitSet(m);
  196. }
  197. if (nb==0)
  198. return;
  199. j = 0;
  200. }
  201. else
  202. {
  203. for (;i<n;i++)
  204. {
  205. bits_t m;
  206. if ((nb>=BitsPerItem)&&(j==0))
  207. {
  208. if (val)
  209. m = (bits_t)-1;
  210. else
  211. m = 0;
  212. nb -= BitsPerItem;
  213. }
  214. else
  215. {
  216. m = getBits(i);
  217. bits_t t = ((bits_t)1)<<j;
  218. for (;j<BitsPerItem;j++)
  219. {
  220. if (val)
  221. m |= t;
  222. else
  223. m &= ~t;
  224. if (--nb==0)
  225. break;
  226. t <<= 1;
  227. }
  228. }
  229. setBits(i, m);
  230. if (nb==0)
  231. return;
  232. j = 0;
  233. }
  234. }
  235. if (val)
  236. {
  237. while (nb>=BitsPerItem)
  238. {
  239. addBitSet((bits_t)-1);
  240. nb -= BitsPerItem;
  241. }
  242. if (nb>0)
  243. {
  244. bits_t m=0;
  245. bits_t t = ((bits_t)1)<<j;
  246. for (;j<BitsPerItem;j++)
  247. {
  248. m |= t;
  249. if (--nb==0)
  250. break;
  251. t <<= 1;
  252. }
  253. addBitSet(m);
  254. }
  255. }
  256. }
  257. public:
  258. // IBitSet impl.
  259. virtual void set(unsigned n, bool val)
  260. {
  261. bits_t t=((bits_t)1)<<(n%BitsPerItem);
  262. unsigned i = n/BitsPerItem;
  263. if (i>=getWidth())
  264. {
  265. if (!val)
  266. return; // don't bother
  267. while (i>getWidth())
  268. addBitSet(0);
  269. addBitSet(t);
  270. }
  271. else
  272. {
  273. bits_t m = getBits(i);
  274. if (val)
  275. m |= t;
  276. else
  277. m &= ~t;
  278. setBits(i, m);
  279. }
  280. }
  281. virtual bool invert(unsigned n)
  282. {
  283. bits_t t=((bits_t)1)<<(n%BitsPerItem);
  284. unsigned i=n/BitsPerItem;
  285. bool ret;
  286. if (i>=getWidth())
  287. {
  288. while (i>getWidth())
  289. addBitSet(0);
  290. addBitSet(t);
  291. ret = true;
  292. }
  293. else
  294. {
  295. bits_t m = getBits(i);
  296. ret = 0 == (m&t);
  297. if (ret)
  298. m |= t;
  299. else
  300. m &= ~t;
  301. setBits(i, m);
  302. }
  303. return ret;
  304. }
  305. virtual bool test(unsigned n)
  306. {
  307. bits_t t=((bits_t)1)<<(n%BitsPerItem);
  308. unsigned i=n/BitsPerItem;
  309. if (i<getWidth())
  310. {
  311. bits_t m = getBits(i);
  312. if (m&t)
  313. return true;
  314. }
  315. return false;
  316. }
  317. virtual bool testSet(unsigned n, bool val)
  318. {
  319. bits_t t=((bits_t)1)<<(n%BitsPerItem);
  320. unsigned i=n/BitsPerItem;
  321. if (i>=getWidth())
  322. {
  323. if (val)
  324. {
  325. while (i>getWidth())
  326. addBitSet(0);
  327. addBitSet(t);
  328. }
  329. return false;
  330. }
  331. else
  332. {
  333. bits_t m = getBits(i);
  334. if (m&t)
  335. {
  336. if (!val)
  337. setBits(i, m & ~t);
  338. return true;
  339. }
  340. else
  341. {
  342. if (val)
  343. setBits(i, m | t);
  344. return false;
  345. }
  346. }
  347. }
  348. virtual unsigned scan(unsigned from,bool tst)
  349. {
  350. return _scan(from,tst,false);
  351. }
  352. virtual unsigned scanInvert(unsigned from,bool tst) // like scan but inverts bit as well
  353. {
  354. return _scan(from,tst,true);
  355. }
  356. virtual void incl(unsigned lo, unsigned hi)
  357. {
  358. _incl(lo,hi,true);
  359. }
  360. virtual void excl(unsigned lo, unsigned hi)
  361. {
  362. _incl(lo,hi,false);
  363. }
  364. };
  365. size32_t getBitSetMemoryRequirement(unsigned numBits)
  366. {
  367. unsigned bitSetUnits = (numBits + (BitsPerItem-1)) / BitsPerItem;
  368. return bitSetUnits * sizeof(bits_t);
  369. }
  370. // Simple BitSet // 0 based all, intermediate items exist, operations threadsafe and atomic
  371. class CBitSetThreadSafe : public CBitSetBase<CBitSetArrayHelper>
  372. {
  373. mutable CriticalSection crit;
  374. void deserialize(MemoryBuffer &buffer)
  375. {
  376. CriticalBlock block(crit);
  377. bits.kill();
  378. unsigned count;
  379. buffer.read(count);
  380. if (count)
  381. {
  382. bits.ensure(count);
  383. while (count--)
  384. {
  385. bits_t b;
  386. buffer.read(b);
  387. bits.append(b);
  388. }
  389. }
  390. }
  391. public:
  392. CBitSetThreadSafe()
  393. {
  394. }
  395. CBitSetThreadSafe(MemoryBuffer &buffer)
  396. {
  397. deserialize(buffer);
  398. }
  399. // IBitSet overloads
  400. virtual void set(unsigned n, bool val)
  401. {
  402. CriticalBlock block(crit);
  403. CBitSetBase::set(n, val);
  404. }
  405. virtual bool invert(unsigned n)
  406. {
  407. CriticalBlock block(crit);
  408. return CBitSetBase::invert(n);
  409. }
  410. virtual bool test(unsigned n)
  411. {
  412. CriticalBlock block(crit);
  413. return CBitSetBase::test(n);
  414. }
  415. virtual bool testSet(unsigned n, bool val)
  416. {
  417. CriticalBlock block(crit);
  418. return CBitSetBase::testSet(n, val);
  419. }
  420. virtual unsigned scan(unsigned from, bool tst)
  421. {
  422. CriticalBlock block(crit);
  423. return _scan(from,tst,false);
  424. }
  425. virtual unsigned scanInvert(unsigned from, bool tst) // like scan but inverts bit as well
  426. {
  427. CriticalBlock block(crit);
  428. return _scan(from,tst,true);
  429. }
  430. virtual void incl(unsigned lo, unsigned hi)
  431. {
  432. CriticalBlock block(crit);
  433. _incl(lo,hi,true);
  434. }
  435. virtual void excl(unsigned lo, unsigned hi)
  436. {
  437. CriticalBlock block(crit);
  438. _incl(lo,hi,false);
  439. }
  440. virtual void reset()
  441. {
  442. CriticalBlock block(crit);
  443. bits.kill();
  444. }
  445. virtual void serialize(MemoryBuffer &buffer) const
  446. {
  447. CriticalBlock block(crit);
  448. buffer.append(bits.ordinality());
  449. ForEachItemIn(b, bits)
  450. buffer.append(bits.item(b));
  451. }
  452. };
  453. extern jlib_decl IBitSet *createThreadSafeBitSet()
  454. {
  455. return new CBitSetThreadSafe();
  456. }
  457. class CBitSet : public CBitSetBase<CBitSetMemoryHelper>
  458. {
  459. void deserialize(MemoryBuffer &buffer)
  460. {
  461. unsigned count;
  462. buffer.read(count);
  463. if (count)
  464. {
  465. unsigned bitSets = count/BitsPerItem;
  466. bitSetUnits = bitSets;
  467. mem = (bits_t *)mb.reserveTruncate(bitSets*sizeof(bits_t));
  468. }
  469. else
  470. {
  471. bitSetUnits = 0;
  472. mem = NULL;
  473. }
  474. fixedMemory = false;
  475. }
  476. public:
  477. CBitSet()
  478. {
  479. // In this form, bitSetUnits and mem will be updated when addBitSet expands mb
  480. }
  481. CBitSet(size32_t memSz, const void *_mem, bool reset)
  482. {
  483. bitSetUnits = memSz*sizeof(byte) / sizeof(bits_t);
  484. mem = (bits_t *)_mem;
  485. if (reset)
  486. memset(mem, 0, bitSetUnits*sizeof(bits_t));
  487. fixedMemory = true;
  488. }
  489. CBitSet(MemoryBuffer &buffer)
  490. {
  491. deserialize(buffer);
  492. }
  493. virtual void reset()
  494. {
  495. memset(mem, 0, sizeof(bits_t)*bitSetUnits);
  496. }
  497. virtual void serialize(MemoryBuffer &buffer) const
  498. {
  499. buffer.append((unsigned)(BitsPerItem*bitSetUnits));
  500. buffer.append(bitSetUnits*sizeof(bits_t), mem);
  501. }
  502. };
  503. extern jlib_decl IBitSet *createBitSet(unsigned maxBits, const void *mem, bool reset)
  504. {
  505. return new CBitSet(maxBits, mem, reset);
  506. }
  507. extern jlib_decl IBitSet *createBitSet()
  508. {
  509. return new CBitSet();
  510. }
  511. // NB: Doubt you'd want to interchange, but serialization formats are compatible
  512. extern jlib_decl IBitSet *deserializeThreadSafeBitSet(MemoryBuffer &mb)
  513. {
  514. return new CBitSetThreadSafe(mb);
  515. }
  516. extern jlib_decl IBitSet *deserializeBitSet(MemoryBuffer &mb)
  517. {
  518. return new CBitSet(mb);
  519. }