jarray.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  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. #ifndef JARRAY_HPP
  14. #define JARRAY_HPP
  15. #include <new>
  16. #include "platform.h"
  17. #include "jiface.hpp"
  18. typedef size32_t aindex_t;
  19. const aindex_t NotFound = (aindex_t)-1;
  20. /************************************************************************
  21. * Copy Lists *
  22. ************************************************************************/
  23. extern "C"
  24. {
  25. typedef int (* StdCompare)(const void *_e1, const void *_e2);
  26. }
  27. /*
  28. * Start of definition:
  29. */
  30. class jlib_decl Allocator
  31. {
  32. public:
  33. void kill();
  34. inline bool isItem(aindex_t pos = 0) const { return pos < used; } /* Is there an item at pos */
  35. inline aindex_t length() const { return used; } /* Return number of items */
  36. inline aindex_t ordinality() const { return used; } /* Return number of items */
  37. inline bool empty() const { return (used==0); }
  38. inline explicit operator bool() const { return (used != 0); }
  39. protected:
  40. void * _doBAdd(void *, size32_t size, StdCompare compare, bool & isNew);
  41. void * _doBSearch(const void *, size32_t size, StdCompare compare) const;
  42. void _doSort(size32_t size, StdCompare compare);
  43. void _ensure(aindex_t, size32_t);
  44. inline void _init() { max=0; _head=0; used=0; } // inline because it is called a lot
  45. void _reallocate(aindex_t newlen, size32_t iSize);
  46. void _doRotateR(aindex_t pos1, aindex_t pos2, size32_t iSize, aindex_t num);
  47. void _doRotateL(aindex_t pos1, aindex_t pos2, size32_t iSize, aindex_t num);
  48. void _space(size32_t iSize);
  49. void _doSwap(aindex_t pos1, aindex_t pos2, size32_t iSize);
  50. void _doTransfer(aindex_t to, aindex_t from, size32_t iSize);
  51. void doSwapWith(Allocator & other);
  52. protected:
  53. void * _head = nullptr;
  54. aindex_t used = 0;
  55. aindex_t max = 0;
  56. };
  57. template <unsigned SIZE> class AllocatorOf : public Allocator
  58. {
  59. public:
  60. inline void ensure(aindex_t num) { _ensure(num, SIZE); }
  61. inline void rotateR(aindex_t pos1, aindex_t pos2) { _doRotateR(pos1, pos2, SIZE, 1); }
  62. inline void rotateL(aindex_t pos1, aindex_t pos2) { _doRotateL(pos1, pos2, SIZE, 1); }
  63. inline void rotateRN(aindex_t pos1, aindex_t pos2, aindex_t num) { _doRotateR(pos1, pos2, SIZE, num); }
  64. inline void rotateLN(aindex_t pos1, aindex_t pos2, aindex_t num) { _doRotateL(pos1, pos2, SIZE, num); }
  65. inline void swap(aindex_t pos1, aindex_t pos2) { _doSwap(pos1, pos2, SIZE); }
  66. inline void transfer(aindex_t to, aindex_t from) { _doTransfer(to, from, SIZE); }
  67. protected:
  68. inline void _space(void) { Allocator::_space(SIZE); }
  69. inline void _move(aindex_t pos1, aindex_t pos2, aindex_t num) { memmove((char *)_head + pos1 * SIZE, (char *)_head + pos2 * SIZE, num * SIZE); }
  70. };
  71. //--------------------------------------------------------------------------------------------------------------------
  72. //Ugly - avoid problems with new being #defined in windows debug mode
  73. #undef new
  74. template <class MEMBER, class PARAM = MEMBER>
  75. class SimpleArrayMapper
  76. {
  77. public:
  78. static void construct(MEMBER & member, PARAM newValue)
  79. {
  80. ::new (&member) MEMBER(newValue);
  81. }
  82. static inline void destruct(MEMBER & member)
  83. {
  84. member.~MEMBER();
  85. }
  86. static inline bool matches(const MEMBER & member, PARAM param)
  87. {
  88. return member == param;
  89. }
  90. static inline PARAM getParameter(const MEMBER & member)
  91. {
  92. return (PARAM)member;
  93. }
  94. };
  95. // An array which stores elements MEMBER, is passed and returns PARAMs
  96. // The MAPPER class is used to map between these two different classes.
  97. template <typename MEMBER, typename PARAM = MEMBER, class MAPPER = SimpleArrayMapper<MEMBER, PARAM> >
  98. class ArrayOf : public AllocatorOf<sizeof(MEMBER)>
  99. {
  100. typedef AllocatorOf<sizeof(MEMBER)> PARENT;
  101. typedef ArrayOf<MEMBER,PARAM,MAPPER> SELF;
  102. protected:
  103. typedef int (*CompareFunc)(const MEMBER *, const MEMBER *); // Should really be const, as should the original array functions
  104. public:
  105. ~ArrayOf<MEMBER,PARAM,MAPPER>() { kill(); }
  106. MEMBER & operator[](size_t pos) { return element((aindex_t)pos); }
  107. const MEMBER & operator[](size_t pos) const { return element((aindex_t)pos); }
  108. inline bool contains(PARAM search) const { return find(search) != NotFound; }
  109. void add(PARAM newValue, aindex_t pos)
  110. {
  111. aindex_t valid_above = SELF::used - pos;
  112. SELF::_space();
  113. SELF::_move(pos + 1, pos, valid_above);
  114. SELF::construct(newValue, pos);
  115. }
  116. void append(PARAM newValue)
  117. {
  118. SELF::_space();
  119. SELF::construct(newValue, SELF::used-1);
  120. }
  121. bool appendUniq(PARAM newValue)
  122. {
  123. if (contains(newValue))
  124. return false;
  125. append(newValue);
  126. return true;
  127. }
  128. aindex_t bAdd(MEMBER & newItem, CompareFunc cf, bool & isNew)
  129. {
  130. SELF::_space();
  131. //MORE: This should have a callback function/method that is used to transfer the new element instead of memcpy
  132. MEMBER * match = (MEMBER *) SELF::_doBAdd(&newItem, sizeof(MEMBER), (StdCompare)cf, isNew);
  133. if (!isNew)
  134. SELF::used--;
  135. MEMBER * head= (MEMBER *)SELF::_head;
  136. return (aindex_t)(match - head);
  137. }
  138. aindex_t bSearch(const MEMBER & key, CompareFunc cf) const
  139. {
  140. MEMBER * head= (MEMBER *)SELF::_head;
  141. MEMBER * match = (MEMBER *) SELF::_doBSearch(&key, sizeof(MEMBER), (StdCompare)cf);
  142. if (match)
  143. return (aindex_t)(match - (MEMBER *)head);
  144. return NotFound;
  145. }
  146. aindex_t find(PARAM searchValue) const
  147. {
  148. MEMBER * head= (MEMBER *)SELF::_head;
  149. for (aindex_t pos = 0; pos < SELF::used; ++pos)
  150. {
  151. if (MAPPER::matches(head[pos], searchValue))
  152. return pos;
  153. }
  154. return NotFound;
  155. }
  156. MEMBER * getArray(aindex_t pos = 0) const
  157. {
  158. MEMBER * head= (MEMBER *)SELF::_head;
  159. assertex(pos <= SELF::used);
  160. return &head[pos];
  161. }
  162. MEMBER * detach()
  163. {
  164. MEMBER * head = (MEMBER *)SELF::_head;
  165. SELF::_init();
  166. return head;
  167. }
  168. void sort(CompareFunc cf)
  169. {
  170. SELF::_doSort(sizeof(MEMBER), (StdCompare)cf);
  171. }
  172. void swap(aindex_t pos1, aindex_t pos2)
  173. {
  174. assertex(SELF::isItem(pos1) && SELF::isItem(pos2));
  175. if (pos1 != pos2)
  176. {
  177. MEMBER * head= (MEMBER *)SELF::_head;
  178. byte temp[sizeof(MEMBER)];
  179. memcpy(temp, head + pos1, sizeof(MEMBER));
  180. memcpy(head + pos1, head + pos2, sizeof(MEMBER));
  181. memcpy(head + pos2, temp, sizeof(MEMBER));
  182. }
  183. }
  184. void swapWith(SELF & other)
  185. {
  186. SELF::doSwapWith(other);
  187. }
  188. void clear()
  189. {
  190. SELF::used = 0;
  191. }
  192. void kill(bool nodestruct = false)
  193. {
  194. aindex_t count = SELF::used;
  195. SELF::used = 0;
  196. if (!nodestruct)
  197. {
  198. for (aindex_t i=0; i<count; i++)
  199. SELF::destruct(i);
  200. }
  201. PARENT::kill();
  202. }
  203. MEMBER & element(aindex_t pos)
  204. {
  205. assertex(SELF::isItem(pos));
  206. MEMBER * head = (MEMBER *)SELF::_head;
  207. return head[pos];
  208. }
  209. const MEMBER & element(aindex_t pos) const
  210. {
  211. assertex(SELF::isItem(pos));
  212. MEMBER * head = (MEMBER *)SELF::_head;
  213. return head[pos];
  214. }
  215. inline PARAM item(aindex_t pos) const
  216. {
  217. assertex(SELF::isItem(pos));
  218. MEMBER * head= (MEMBER *)SELF::_head;
  219. return MAPPER::getParameter(head[pos]);
  220. }
  221. void remove(aindex_t pos, bool nodestruct = false)
  222. {
  223. assertex(pos < SELF::used);
  224. SELF::used --;
  225. if (!nodestruct) SELF::destruct(pos);
  226. SELF::_move( pos, pos + 1, ( SELF::used - pos ) );
  227. }
  228. void removen(aindex_t pos, aindex_t num, bool nodestruct = false)
  229. {
  230. assertex(pos + num <= SELF::used);
  231. SELF::used -= num;
  232. if (!nodestruct)
  233. {
  234. unsigned idx = 0;
  235. for (;idx < num; idx++)
  236. SELF::destruct(pos+idx);
  237. }
  238. SELF::_move( pos, pos + num, ( SELF::used - pos ) );
  239. }
  240. void pop(bool nodestruct = false)
  241. {
  242. assertex(SELF::used);
  243. --SELF::used;
  244. if (!nodestruct)
  245. SELF::destruct(SELF::used);
  246. }
  247. PARAM popGet()
  248. {
  249. assertex(SELF::used);
  250. --SELF::used;
  251. MEMBER * head= (MEMBER *)SELF::_head;
  252. return MAPPER::getParameter(head[SELF::used]); // used already decremented so element() would assert
  253. }
  254. void popn(aindex_t n, bool nodestruct = false)
  255. {
  256. assertex(SELF::used>=n);
  257. while (n--)
  258. {
  259. --SELF::used;
  260. if (!nodestruct)
  261. SELF::destruct(SELF::used);
  262. }
  263. }
  264. void popAll(bool nodestruct = false)
  265. {
  266. if (!nodestruct)
  267. {
  268. while (SELF::used)
  269. SELF::destruct(--SELF::used);
  270. }
  271. else
  272. SELF::used = 0;
  273. }
  274. void replace(PARAM newValue, aindex_t pos, bool nodestruct = false)
  275. {
  276. assertex(SELF::isItem(pos));
  277. if (!nodestruct)
  278. SELF::destruct(pos);
  279. SELF::construct(newValue, pos);
  280. }
  281. const MEMBER & last(void) const
  282. {
  283. return element(SELF::used-1);
  284. }
  285. const MEMBER & last(aindex_t n) const
  286. {
  287. return element(SELF::used-n-1);
  288. }
  289. MEMBER & last(void)
  290. {
  291. return element(SELF::used-1);
  292. }
  293. MEMBER & last(aindex_t n)
  294. {
  295. return element(SELF::used-n-1);
  296. }
  297. PARAM tos(void) const
  298. {
  299. return MAPPER::getParameter(element(SELF::used-1));
  300. }
  301. PARAM tos(aindex_t n) const
  302. {
  303. return MAPPER::getParameter(element(SELF::used-n-1));
  304. }
  305. void trunc(aindex_t limit, bool nodestruct = false)
  306. {
  307. while (limit < SELF::used)
  308. SELF::pop(nodestruct);
  309. }
  310. bool zap(PARAM searchValue, bool nodestruct = false)
  311. {
  312. MEMBER * head= (MEMBER *)SELF::_head;
  313. for (aindex_t pos= 0; pos < SELF::used; ++pos)
  314. {
  315. if (MAPPER::matches(head[pos], searchValue))
  316. {
  317. remove(pos, nodestruct);
  318. return true;
  319. }
  320. }
  321. return false;
  322. }
  323. protected:
  324. inline void construct(PARAM newValue, unsigned pos)
  325. {
  326. MEMBER * head= (MEMBER *)SELF::_head;
  327. MAPPER::construct(head[pos], newValue);
  328. }
  329. inline void destruct(unsigned pos)
  330. {
  331. MEMBER * head= (MEMBER *)SELF::_head;
  332. MAPPER::destruct(head[pos]);
  333. }
  334. };
  335. //--------------------------------------------------------------------------------------------------------------------
  336. template <typename ITEM>
  337. class OwnedReferenceArrayMapper
  338. {
  339. typedef ITEM * MEMBER;
  340. typedef ITEM & PARAM;
  341. public:
  342. static void construct(MEMBER & member, PARAM newValue)
  343. {
  344. member = &newValue;
  345. }
  346. static void destruct(MEMBER & member)
  347. {
  348. member->Release();
  349. }
  350. static inline bool matches(const MEMBER & member, PARAM param)
  351. {
  352. return member == &param;
  353. }
  354. static inline PARAM getParameter(const MEMBER & member)
  355. {
  356. return *member;
  357. }
  358. };
  359. // An array which stores owned references to elements of type INTERFACE
  360. template <class INTERFACE>
  361. class OwnedReferenceArrayOf : public ArrayOf<INTERFACE *, INTERFACE &, OwnedReferenceArrayMapper<INTERFACE> >
  362. {
  363. };
  364. //--------------------------------------------------------------------------------------------------------------------
  365. template <typename ITEM>
  366. class OwnedPointerArrayMapper : public SimpleArrayMapper<ITEM*>
  367. {
  368. typedef ITEM * MEMBER;
  369. typedef ITEM * PARAM;
  370. public:
  371. static void destruct(MEMBER & member)
  372. {
  373. ::Release(member);
  374. }
  375. };
  376. // An array which stores owned pointers to elements of type INTERFACE
  377. template <typename INTERFACE>
  378. class OwnedPointerArrayOf : public ArrayOf<INTERFACE *, INTERFACE *, OwnedPointerArrayMapper<INTERFACE> >
  379. {
  380. };
  381. template <typename INTERFACE>
  382. class OwnedConstPointerArrayOf : public ArrayOf<const INTERFACE *, const INTERFACE *, OwnedPointerArrayMapper<const INTERFACE> >
  383. {
  384. };
  385. //--------------------------------------------------------------------------------------------------------------------
  386. template <typename ITEM>
  387. class SafePointerArrayMapper : public SimpleArrayMapper<ITEM*>
  388. {
  389. typedef ITEM * MEMBER;
  390. typedef ITEM * PARAM;
  391. public:
  392. static void destruct(MEMBER & member)
  393. {
  394. delete member;
  395. }
  396. };
  397. // An array which stores owned pointers to elements of type INTERFACE, and calls delete when they are released.
  398. template <typename INTERFACE>
  399. class SafePointerArrayOf : public ArrayOf<INTERFACE *, INTERFACE *, SafePointerArrayMapper<INTERFACE> >
  400. {
  401. };
  402. //--------------------------------------------------------------------------------------------------------------------
  403. template <class ITEM>
  404. class ReferenceArrayMapper
  405. {
  406. public:
  407. static void construct(ITEM * & member, ITEM & newValue)
  408. {
  409. member = &newValue;
  410. }
  411. static inline void destruct(ITEM * & member __attribute__((unused)))
  412. {
  413. }
  414. static inline bool matches(ITEM * const & member, ITEM & param)
  415. {
  416. return member == &param;
  417. }
  418. static inline ITEM & getParameter(ITEM * const & member)
  419. {
  420. return *member;
  421. }
  422. };
  423. // An array which stores pointers to INTERFACE, but passes and returns references.
  424. template <class INTERFACE>
  425. class CopyReferenceArrayOf : public ArrayOf<INTERFACE *, INTERFACE &, ReferenceArrayMapper<INTERFACE> >
  426. {
  427. };
  428. //--------------------------------------------------------------------------------------------------------------------
  429. template <typename CLASS>
  430. class StructArrayOf : public ArrayOf<CLASS, const CLASS &> { };
  431. //--------------------------------------------------------------------------------------------------------------------
  432. template <class ARRAY, class PARAM> class ArrayIteratorOf
  433. {
  434. public:
  435. ArrayIteratorOf(ARRAY & _array) : array(_array) { cur = 0; }
  436. inline bool first(void) { cur = 0; return isValid(); }
  437. inline bool isValid(void) { return array.isItem(cur); }
  438. inline PARAM query() { assertex(isValid()); return array.item(cur); }
  439. inline bool hasNext(void) { return array.isItem(cur+1); }
  440. inline bool hasPrev(void) { return array.isItem(cur-1); }
  441. inline bool last(void) { cur = array.ordinality()-1; return isValid(); }
  442. inline bool next(void) { ++cur; return isValid(); }
  443. inline bool prev(void) { --cur; return isValid(); }
  444. inline bool select(aindex_t seek) { cur = seek; return isValid(); }
  445. private:
  446. ARRAY & array;
  447. aindex_t cur;
  448. };
  449. #define ForEachItem(x) aindex_t numItems##x = ordinality(); \
  450. aindex_t x = 0; \
  451. for (; x< numItems##x; ++x)
  452. #define ForEachItemRev(x) aindex_t x = ordinality(); \
  453. for (;x--;)
  454. #define ForEachItemIn(x,y) aindex_t numItems##x = (y).ordinality(); \
  455. aindex_t x = 0; \
  456. for (; x< numItems##x; ++x)
  457. #define ForEachItemInRev(x,y) aindex_t x = (y).ordinality(); \
  458. for (;x--;)
  459. #define CloneArray(TGT, SRC) \
  460. { ForEachItemIn(idx##__LINE__, SRC) \
  461. (TGT).append((SRC).item(idx##__LINE__)); }
  462. /*
  463. Documentation on the template classes:
  464. CopyReferenceArrayOf<X>
  465. An array of references to objects/interfaces of type X. This array doesn't link count.
  466. OwnedReferenceArrayOf<X> {};
  467. An array of references to link counted objects/interfaces of type X. The array takes ownership of the items
  468. that are added to it, and will be released when they are removed.
  469. OwnedPointerArrayOf<X> {};
  470. An array of pointers to link counted objects/interfaces of type X (which may be NULL). The array takes
  471. ownership of the items that are added to it, and will be released when they are removed.
  472. SafePointerArrayOf<IInterface> {};
  473. An array of pointers to objects/interfaces of type X (may include NULL). The array takes ownership of the
  474. items that are added to it, and will be deleted when they are removed.
  475. ArrayOf<X> {}
  476. An array of objects of type X. This is normally used for simple types e.g., unsigned or pointers
  477. StructArrayOf<X> {}
  478. An array of objects of type X. This is used where X is a class type because items are passed.
  479. Copy constructors are called when items are added, and destructors when they are removed.
  480. ArrayOf<MEMBER, PARAM, MAPPING> {}
  481. The base array implementation which stores elements of type MEMBER, and elements of type PARAM are added.
  482. The MAPPING class configures how MEMBERs are mapped to PARAMs, and the operations performed when items
  483. are added or removed from the array.
  484. */
  485. #endif