jset.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  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. // Simple BitSet // 0 based all, intermediate items exist, operations threadsafe and atomic
  19. class CBitSet : public CInterface, implements IBitSet
  20. {
  21. public:
  22. IMPLEMENT_IINTERFACE;
  23. protected:
  24. //unsigned seems to be most efficient, and required for __builtin_ffs below
  25. typedef unsigned bits_t;
  26. enum { BitsPerItem = sizeof(bits_t) * 8 };
  27. ArrayOf<bits_t> bits;
  28. mutable CriticalSection crit;
  29. public:
  30. CBitSet() { }
  31. CBitSet(MemoryBuffer &buffer)
  32. {
  33. deserialize(buffer);
  34. }
  35. void set(unsigned n,bool val)
  36. {
  37. bits_t t=((bits_t)1)<<(n%BitsPerItem);
  38. unsigned i=n/BitsPerItem;
  39. CriticalBlock block(crit);
  40. if (i>=bits.ordinality()) {
  41. if (!val)
  42. return; // don't bother
  43. while (i>bits.ordinality())
  44. bits.append(0);
  45. bits.append(t);
  46. }
  47. else {
  48. bits_t m=bits.item(i);
  49. if (val)
  50. m |= t;
  51. else
  52. m &= ~t;
  53. bits.replace(m,i);
  54. }
  55. }
  56. bool invert(unsigned n)
  57. {
  58. bits_t t=((bits_t)1)<<(n%BitsPerItem);
  59. unsigned i=n/BitsPerItem;
  60. CriticalBlock block(crit);
  61. bool ret;
  62. if (i>=bits.ordinality()) {
  63. while (i>bits.ordinality())
  64. bits.append(0);
  65. bits.append(t);
  66. ret = true;
  67. }
  68. else {
  69. bits_t m=bits.item(i);
  70. ret = ((m&t)==0);
  71. if (ret)
  72. m |= t;
  73. else
  74. m &= ~t;
  75. bits.replace(m,i);
  76. }
  77. return ret;
  78. }
  79. bool test(unsigned n)
  80. {
  81. bits_t t=((bits_t)1)<<(n%BitsPerItem);
  82. unsigned i=n/BitsPerItem;
  83. CriticalBlock block(crit);
  84. if (i<bits.ordinality()) {
  85. bits_t m=bits.item(i);
  86. if (m&t)
  87. return true;
  88. }
  89. return false;
  90. }
  91. bool testSet(unsigned n,bool val)
  92. {
  93. bits_t t=((bits_t)1)<<(n%BitsPerItem);
  94. unsigned i=n/BitsPerItem;
  95. CriticalBlock block(crit);
  96. bool ret;
  97. if (i>=bits.ordinality()) {
  98. ret = false;
  99. if (!val)
  100. return false; // don't bother
  101. while (i>bits.ordinality())
  102. bits.append(0);
  103. bits.append(t);
  104. }
  105. else {
  106. bits_t m=bits.item(i);
  107. ret = (m&t)!=0;
  108. if (val)
  109. m |= t;
  110. else
  111. m &= ~t;
  112. bits.replace(m,i);
  113. }
  114. return ret;
  115. }
  116. unsigned _scan(unsigned from,bool tst,bool scninv)
  117. {
  118. bits_t noMatchMask=tst?0:(bits_t)-1;
  119. unsigned j=from%BitsPerItem;
  120. CriticalBlock block(crit);
  121. // returns index of first = val >= from
  122. unsigned n=bits.ordinality();
  123. unsigned i;
  124. for (i=from/BitsPerItem;i<n;i++)
  125. {
  126. bits_t m=bits.item(i);
  127. if (m!=noMatchMask)
  128. {
  129. #if defined(__GNUC__)
  130. //Use the __builtin_ffs instead of a loop to find the first bit set/cleared
  131. bits_t testMask = m;
  132. if (j != 0)
  133. {
  134. //Set all the bottom bits to the value we're not searching for
  135. bits_t mask = (((bits_t)1)<<j)-1;
  136. if (tst)
  137. testMask &= ~mask;
  138. else
  139. testMask |= mask;
  140. //May possibly match exactly - if so continue main loop
  141. if (testMask==noMatchMask)
  142. {
  143. j = 0;
  144. continue;
  145. }
  146. }
  147. //Guaranteed a match at this point
  148. if (tst)
  149. {
  150. //Returns one plus the index of the least significant 1-bit of testMask
  151. //(testMask != 0) since that has been checked above (noMatchMask == 0)
  152. unsigned pos = __builtin_ffs(testMask)-1;
  153. if (scninv)
  154. {
  155. bits_t t = ((bits_t)1)<<pos;
  156. m &= ~t;
  157. bits.replace(m,i);
  158. }
  159. return i*BitsPerItem+pos;
  160. }
  161. else
  162. {
  163. //Same as above but invert the bitmask
  164. unsigned pos = __builtin_ffs(~testMask)-1;
  165. if (scninv)
  166. {
  167. bits_t t = ((bits_t)1)<<pos;
  168. m |= t;
  169. bits.replace(m,i);
  170. }
  171. return i*BitsPerItem+pos;
  172. }
  173. #else
  174. bits_t t = ((bits_t)1)<<j;
  175. for (;j<BitsPerItem;j++)
  176. {
  177. if (t&m)
  178. {
  179. if (tst)
  180. {
  181. if (scninv)
  182. {
  183. m &= ~t;
  184. bits.replace(m,i);
  185. }
  186. return i*BitsPerItem+j;
  187. }
  188. }
  189. else
  190. {
  191. if (!tst)
  192. {
  193. if (scninv)
  194. {
  195. m |= t;
  196. bits.replace(m,i);
  197. }
  198. return i*BitsPerItem+j;
  199. }
  200. }
  201. t <<= 1;
  202. }
  203. #endif
  204. }
  205. j = 0;
  206. }
  207. if (tst)
  208. return (unsigned)-1;
  209. unsigned ret = n*BitsPerItem;
  210. if (n*BitsPerItem<from)
  211. ret = from;
  212. if (scninv)
  213. set(ret,true);
  214. return ret;
  215. }
  216. unsigned scan(unsigned from,bool tst)
  217. {
  218. return _scan(from,tst,false);
  219. }
  220. unsigned scanInvert(unsigned from,bool tst) // like scan but inverts bit as well
  221. {
  222. return _scan(from,tst,true);
  223. }
  224. void _incl(unsigned lo, unsigned hi,bool val)
  225. {
  226. if (hi<lo)
  227. return;
  228. unsigned j=lo%BitsPerItem;
  229. unsigned nb=(hi-lo)+1;
  230. CriticalBlock block(crit);
  231. unsigned n=bits.ordinality();
  232. unsigned i;
  233. for (i=lo/BitsPerItem;i<n;i++) {
  234. bits_t m;
  235. if ((nb>=BitsPerItem)&&(j==0)) {
  236. m = i;
  237. nb -= BitsPerItem;
  238. }
  239. else {
  240. m=bits.item(i);
  241. bits_t t = ((bits_t)1)<<j;
  242. for (;j<BitsPerItem;j++) {
  243. if (val)
  244. m |= t;
  245. else
  246. m &= ~t;
  247. if (--nb==0)
  248. break;
  249. t <<= 1;
  250. }
  251. }
  252. bits.replace(m,i);
  253. if (nb==0)
  254. return;
  255. j = 0;
  256. }
  257. if (val) {
  258. while (nb>=BitsPerItem) {
  259. bits.append((bits_t)-1);
  260. nb-=BitsPerItem;
  261. }
  262. if (nb>0) {
  263. bits_t m=0;
  264. bits_t t = ((bits_t)1)<<j;
  265. for (;j<BitsPerItem;j++) {
  266. m |= t;
  267. if (--nb==0)
  268. break;
  269. t <<= 1;
  270. }
  271. bits.append(m);
  272. }
  273. }
  274. }
  275. void incl(unsigned lo, unsigned hi)
  276. {
  277. _incl(lo,hi,true);
  278. }
  279. void excl(unsigned lo, unsigned hi)
  280. {
  281. _incl(lo,hi,false);
  282. }
  283. void reset()
  284. {
  285. CriticalBlock block(crit);
  286. bits.kill();
  287. }
  288. void serialize(MemoryBuffer &buffer) const
  289. {
  290. CriticalBlock block(crit);
  291. buffer.append(bits.ordinality());
  292. ForEachItemIn(b, bits)
  293. buffer.append(bits.item(b));
  294. }
  295. void deserialize(MemoryBuffer &buffer)
  296. {
  297. CriticalBlock block(crit);
  298. bits.kill();
  299. unsigned count;
  300. buffer.read(count);
  301. if (count)
  302. {
  303. bits.ensure(count);
  304. while (count--)
  305. {
  306. bits_t b;
  307. buffer.read(b);
  308. bits.append(b);
  309. }
  310. }
  311. }
  312. };
  313. extern jlib_decl IBitSet *createBitSet()
  314. {
  315. return new CBitSet();
  316. }
  317. extern jlib_decl IBitSet *deserializeIBitSet(MemoryBuffer &mb)
  318. {
  319. return new CBitSet(mb);
  320. }