/src/util/parray.h

http://z3.codeplex.com · C Header · 621 lines · 553 code · 48 blank · 20 comment · 115 complexity · 95d462dd11c9d921a2b1f8a0b9f30c42 MD5 · raw file

  1. /*++
  2. Copyright (c) 2011 Microsoft Corporation
  3. Module Name:
  4. parray.h
  5. Abstract:
  6. Persistent Arrays.
  7. Author:
  8. Leonardo de Moura (leonardo) 2011-02-21.
  9. Revision History:
  10. --*/
  11. #ifndef _PARRAY_H_
  12. #define _PARRAY_H_
  13. #include"vector.h"
  14. #include"trace.h"
  15. template<typename C>
  16. class parray_manager {
  17. public:
  18. typedef typename C::value value;
  19. typedef typename C::value_manager value_manager;
  20. typedef typename C::allocator allocator;
  21. private:
  22. static size_t capacity(value * vs) {
  23. return vs == 0 ? 0 : (reinterpret_cast<size_t*>(vs))[-1];
  24. }
  25. value * allocate_values(size_t c) {
  26. size_t * mem = static_cast<size_t*>(m_allocator.allocate(sizeof(value)*c + sizeof(size_t)));
  27. *mem = c;
  28. ++mem;
  29. value * r = reinterpret_cast<value*>(mem);
  30. SASSERT(capacity(r) == c);
  31. TRACE("parray_mem", tout << "allocated values[" << c << "]: " << r << "\n";);
  32. return r;
  33. }
  34. void deallocate_values(value * vs) {
  35. if (vs == 0)
  36. return;
  37. size_t c = capacity(vs);
  38. TRACE("parray_mem", tout << "deallocated values[" << c << "]: " << vs << "\n";);
  39. size_t * mem = reinterpret_cast<size_t*>(vs);
  40. --mem;
  41. m_allocator.deallocate(sizeof(value)*c + sizeof(size_t), mem);
  42. }
  43. enum ckind { SET, PUSH_BACK, POP_BACK, ROOT };
  44. struct cell {
  45. unsigned m_ref_count:30;
  46. unsigned m_kind:2;
  47. union {
  48. unsigned m_idx;
  49. unsigned m_size;
  50. };
  51. value m_elem;
  52. union {
  53. cell * m_next;
  54. value * m_values;
  55. };
  56. ckind kind() const { return static_cast<ckind>(m_kind); }
  57. unsigned idx() const { SASSERT(kind() != ROOT); return m_idx; }
  58. unsigned size() const { SASSERT(kind() == ROOT); return m_size; }
  59. cell * next() const { SASSERT(kind() != ROOT); return m_next; }
  60. value const & elem() const { SASSERT(kind() == SET || kind() == PUSH_BACK); return m_elem; }
  61. cell(ckind k):m_ref_count(1), m_kind(k), m_size(0), m_values(0) {}
  62. };
  63. value_manager & m_vmanager;
  64. allocator & m_allocator;
  65. ptr_vector<cell> m_get_values_tmp;
  66. ptr_vector<cell> m_reroot_tmp;
  67. void inc_ref(value const & v) {
  68. if (C::ref_count)
  69. m_vmanager.inc_ref(v);
  70. }
  71. void dec_ref(value const & v) {
  72. if (C::ref_count)
  73. m_vmanager.dec_ref(v);
  74. }
  75. void dec_ref(unsigned sz, value * vs) {
  76. if (C::ref_count)
  77. for (unsigned i = 0; i < sz; i++)
  78. m_vmanager.dec_ref(vs[i]);
  79. }
  80. cell * mk(ckind k) {
  81. cell * r = new (m_allocator.allocate(sizeof(cell))) cell(k);
  82. TRACE("parray_mem", tout << "allocated cell: " << r << "\n";);
  83. return r;
  84. }
  85. void del(cell * c) {
  86. while (true) {
  87. cell * next = 0;
  88. switch (c->kind()) {
  89. case SET:
  90. case PUSH_BACK:
  91. dec_ref(c->elem());
  92. next = c->next();
  93. break;
  94. case POP_BACK:
  95. next = c->next();
  96. break;
  97. case ROOT:
  98. dec_ref(c->size(), c->m_values);
  99. deallocate_values(c->m_values);
  100. break;
  101. }
  102. TRACE("parray_mem", tout << "deallocated cell: " << c << "\n";);
  103. c->~cell();
  104. m_allocator.deallocate(sizeof(cell), c);
  105. if (next == 0)
  106. return;
  107. SASSERT(next->m_ref_count > 0);
  108. next->m_ref_count--;
  109. if (next->m_ref_count > 0)
  110. return;
  111. c = next;
  112. }
  113. }
  114. void inc_ref(cell * c) {
  115. if (!c) return;
  116. c->m_ref_count++;
  117. }
  118. void dec_ref(cell * c) {
  119. if (!c) return;
  120. TRACE("parray_mem", tout << "dec_ref(" << c << "), ref_count: " << c->m_ref_count << "\n";);
  121. SASSERT(c->m_ref_count > 0);
  122. c->m_ref_count--;
  123. if (c->m_ref_count == 0)
  124. del(c);
  125. }
  126. void expand(value * & vs) {
  127. size_t curr_capacity = capacity(vs);
  128. size_t new_capacity = curr_capacity == 0 ? 2 : (3 * curr_capacity + 1) >> 1;
  129. value * new_vs = allocate_values(new_capacity);
  130. if (curr_capacity > 0) {
  131. for (size_t i = 0; i < curr_capacity; i++)
  132. new_vs[i] = vs[i];
  133. deallocate_values(vs);
  134. }
  135. vs = new_vs;
  136. }
  137. void rset(value * vs, unsigned i, value const & v) {
  138. inc_ref(v);
  139. dec_ref(vs[i]);
  140. vs[i] = v;
  141. }
  142. void rset(cell * c, unsigned i, value const & v) {
  143. SASSERT(c->kind() == ROOT);
  144. SASSERT(i < c->size());
  145. rset(c->m_values, i, v);
  146. }
  147. void rpush_back(value * & vs, unsigned & sz, value const & v) {
  148. if (sz == capacity(vs))
  149. expand(vs);
  150. SASSERT(sz < capacity(vs));
  151. inc_ref(v);
  152. vs[sz] = v;
  153. sz++;
  154. }
  155. void rpush_back(cell * c, value const & v) {
  156. SASSERT(c->kind() == ROOT);
  157. rpush_back(c->m_values, c->m_size, v);
  158. }
  159. void rpop_back(value * vs, unsigned & sz) {
  160. sz--;
  161. dec_ref(vs[sz]);
  162. }
  163. void rpop_back(cell * c) {
  164. SASSERT(c->kind() == ROOT);
  165. rpop_back(c->m_values, c->m_size);
  166. }
  167. void copy_values(value * s, unsigned sz, value * & t) {
  168. SASSERT(t == 0);
  169. t = allocate_values(capacity(s));
  170. for (unsigned i = 0; i < sz; i++) {
  171. t[i] = s[i];
  172. inc_ref(t[i]);
  173. }
  174. }
  175. unsigned get_values(cell * s, value * & vs) {
  176. ptr_vector<cell> & cs = m_get_values_tmp;
  177. cs.reset();
  178. cell * r = s;
  179. while (r->kind() != ROOT) {
  180. cs.push_back(r);
  181. r = r->next();
  182. }
  183. SASSERT(r->kind() == ROOT);
  184. unsigned sz = r->m_size;
  185. vs = 0;
  186. copy_values(r->m_values, sz, vs);
  187. unsigned i = cs.size();
  188. while (i > 0) {
  189. --i;
  190. cell * curr = cs[i];
  191. switch (curr->kind()) {
  192. case SET:
  193. rset(vs, curr->m_idx, curr->m_elem);
  194. break;
  195. case POP_BACK:
  196. rpop_back(vs, sz);
  197. break;
  198. case PUSH_BACK:
  199. rpush_back(vs, sz, curr->m_elem);
  200. break;
  201. case ROOT:
  202. UNREACHABLE();
  203. break;
  204. }
  205. }
  206. return sz;
  207. }
  208. void unfold(cell * c) {
  209. if (c->kind() == ROOT)
  210. return;
  211. value * vs;
  212. unsigned sz = get_values(c, vs);
  213. dec_ref(c->m_next);
  214. if (c->kind() == SET || c->kind() == PUSH_BACK)
  215. dec_ref(c->m_elem);
  216. c->m_next = 0;
  217. c->m_kind = ROOT;
  218. c->m_size = sz;
  219. c->m_values = vs;
  220. SASSERT(c->kind() == ROOT);
  221. }
  222. public:
  223. class ref {
  224. cell * m_ref;
  225. unsigned m_updt_counter; // counter for minimizing memory consumption when using preserve_roots option
  226. ref(cell * r):m_ref(r), m_updt_counter(0) {}
  227. bool root() const { return m_ref->kind() == ROOT; }
  228. bool unshared() const { return m_ref->m_ref_count == 1; }
  229. friend class parray_manager;
  230. public:
  231. ref():m_ref(0), m_updt_counter(0) {}
  232. };
  233. public:
  234. parray_manager(value_manager & m, allocator & a):
  235. m_vmanager(m),
  236. m_allocator(a) {
  237. }
  238. value_manager & manager() { return m_vmanager; }
  239. void mk(ref & r) {
  240. dec_ref(r.m_ref);
  241. cell * new_c = mk(ROOT);
  242. r.m_ref = new_c;
  243. r.m_updt_counter = 0;
  244. SASSERT(new_c->m_ref_count == 1);
  245. }
  246. void del(ref & r) {
  247. dec_ref(r.m_ref);
  248. r.m_ref = 0;
  249. r.m_updt_counter = 0;
  250. }
  251. void copy(ref const & s, ref & t) {
  252. inc_ref(s.m_ref);
  253. dec_ref(t.m_ref);
  254. t.m_ref = s.m_ref;
  255. t.m_updt_counter = 0;
  256. }
  257. unsigned size(ref const & r) const {
  258. cell * c = r.m_ref;
  259. if (c == 0) return 0;
  260. while (true) {
  261. switch (c->kind()) {
  262. case SET:
  263. c = c->next();
  264. break;
  265. case PUSH_BACK:
  266. return c->idx() + 1;
  267. case POP_BACK:
  268. return c->idx() - 1;
  269. case ROOT:
  270. return c->size();
  271. }
  272. }
  273. }
  274. bool empty(ref const & r) const { return size(r) == 0; }
  275. value const & get(ref const & r, unsigned i) const {
  276. SASSERT(i < size(r));
  277. unsigned trail_sz = 0;
  278. cell * c = r.m_ref;
  279. while (true) {
  280. if (trail_sz > C::max_trail_sz) {
  281. const_cast<parray_manager*>(this)->reroot(const_cast<ref&>(r));
  282. SASSERT(r.m_ref->kind() == ROOT);
  283. return r.m_ref->m_values[i];
  284. }
  285. switch (c->kind()) {
  286. case SET:
  287. case PUSH_BACK:
  288. if (i == c->idx())
  289. return c->elem();
  290. trail_sz++;
  291. c = c->next();
  292. break;
  293. case POP_BACK:
  294. trail_sz++;
  295. c = c->next();
  296. break;
  297. case ROOT:
  298. return c->m_values[i];
  299. }
  300. }
  301. }
  302. void set(ref & r, unsigned i, value const & v) {
  303. SASSERT(i < size(r));
  304. if (r.root()) {
  305. if (r.unshared()) {
  306. rset(r.m_ref, i, v);
  307. return;
  308. }
  309. if (C::preserve_roots) {
  310. if (r.m_updt_counter > size(r)) {
  311. unshare(r);
  312. SASSERT(r.unshared());
  313. SASSERT(r.m_updt_counter == 0);
  314. rset(r.m_ref, i, v);
  315. return;
  316. }
  317. r.m_updt_counter++;
  318. cell * c = r.m_ref;
  319. cell * new_c = mk(ROOT);
  320. new_c->m_size = c->m_size;
  321. new_c->m_values = c->m_values;
  322. inc_ref(new_c);
  323. c->m_kind = SET;
  324. c->m_idx = i;
  325. c->m_elem = c->m_values[i];
  326. inc_ref(c->m_elem);
  327. c->m_next = new_c;
  328. dec_ref(c);
  329. r.m_ref = new_c;
  330. rset(new_c, i, v);
  331. SASSERT(new_c->m_ref_count == 2);
  332. return;
  333. }
  334. }
  335. cell * new_c = mk(SET);
  336. new_c->m_idx = i;
  337. inc_ref(v);
  338. new_c->m_elem = v;
  339. new_c->m_next = r.m_ref;
  340. r.m_ref = new_c;
  341. SASSERT(new_c->m_ref_count == 1);
  342. }
  343. void set(ref const & s, unsigned i, value const & v, ref & r) {
  344. SASSERT(i < size(s));
  345. if (&s == &r) {
  346. set(r, i, v);
  347. return;
  348. }
  349. copy(s, r);
  350. set(r, i, v);
  351. }
  352. void push_back(ref & r, value const & v) {
  353. if (r.m_ref == 0)
  354. mk(r);
  355. if (r.root()) {
  356. if (r.unshared()) {
  357. rpush_back(r.m_ref, v);
  358. return;
  359. }
  360. if (C::preserve_roots) {
  361. if (r.m_updt_counter > size(r)) {
  362. unshare(r);
  363. SASSERT(r.unshared());
  364. SASSERT(r.m_updt_counter == 0);
  365. rpush_back(r.m_ref, v);
  366. return;
  367. }
  368. r.m_updt_counter++;
  369. cell * c = r.m_ref;
  370. SASSERT(c->m_ref_count > 1);
  371. cell * new_c = mk(ROOT);
  372. new_c->m_size = c->m_size;
  373. new_c->m_values = c->m_values;
  374. inc_ref(new_c);
  375. c->m_kind = POP_BACK;
  376. c->m_idx = new_c->m_size + 1;
  377. c->m_next = new_c;
  378. dec_ref(c);
  379. r.m_ref = new_c;
  380. rpush_back(new_c, v);
  381. SASSERT(new_c->m_ref_count == 2);
  382. return;
  383. }
  384. }
  385. cell * new_c = mk(PUSH_BACK);
  386. new_c->m_idx = size(r.m_ref);
  387. inc_ref(v);
  388. new_c->m_elem = v;
  389. new_c->m_next = r.m_ref;
  390. r.m_ref = new_c;
  391. SASSERT(new_c->m_ref_count == 1);
  392. }
  393. void push_back(ref const & s, value const & v, ref & r) {
  394. if (&s == &r) {
  395. push_back(r, v);
  396. return;
  397. }
  398. copy(s, r);
  399. push_back(r, v);
  400. }
  401. void pop_back(ref & r) {
  402. SASSERT(!empty(r));
  403. if (r.root()) {
  404. if (r.unshared()) {
  405. rpop_back(r.m_ref);
  406. return;
  407. }
  408. if (C::preserve_roots) {
  409. if (r.m_updt_counter > size(r)) {
  410. unshare(r);
  411. SASSERT(r.unshared());
  412. SASSERT(r.m_updt_counter == 0);
  413. rpop_back(r.m_ref);
  414. return;
  415. }
  416. r.m_updt_counter++;
  417. cell * c = r.m_ref;
  418. SASSERT(c->m_ref_count > 1);
  419. cell * new_c = mk(ROOT);
  420. new_c->m_size = c->m_size;
  421. new_c->m_values = c->m_values;
  422. inc_ref(new_c);
  423. c->m_kind = PUSH_BACK;
  424. c->m_idx = new_c->m_size - 1;
  425. c->m_elem = new_c->m_values[c->m_idx];
  426. inc_ref(c->m_elem);
  427. c->m_next = new_c;
  428. dec_ref(c);
  429. r.m_ref = new_c;
  430. rpop_back(new_c);
  431. SASSERT(new_c->m_ref_count == 2);
  432. return;
  433. }
  434. }
  435. cell * new_c = mk(POP_BACK);
  436. new_c->m_idx = size(r.m_ref);
  437. new_c->m_next = r.m_ref;
  438. r.m_ref = new_c;
  439. SASSERT(new_c->m_ref_count == 1);
  440. }
  441. void pop_back(ref const & s, ref & r) {
  442. SASSERT(!empty(s));
  443. if (&s == &r) {
  444. pop_back(r);
  445. return;
  446. }
  447. copy(s, r);
  448. pop_back(r);
  449. }
  450. void unshare(ref & r) {
  451. if (r.root() && r.unshared())
  452. return;
  453. cell * c = r.m_ref;
  454. cell * new_c = mk(ROOT);
  455. new_c->m_size = get_values(c, new_c->m_values);
  456. SASSERT(new_c->m_ref_count == 1);
  457. dec_ref(c);
  458. r.m_ref = new_c;
  459. r.m_updt_counter = 0;
  460. SASSERT(r.root());
  461. SASSERT(r.unshared());
  462. }
  463. void unfold(ref & r) {
  464. if (r.root())
  465. return;
  466. unfold(r.m_ref);
  467. r.m_updt_counter = 0;
  468. SASSERT(r.root());
  469. }
  470. void reroot(ref & r) {
  471. if (r.root())
  472. return;
  473. ptr_vector<cell> & cs = m_reroot_tmp;
  474. cs.reset();
  475. unsigned r_sz = size(r);
  476. unsigned trail_split_idx = r_sz / C::factor;
  477. unsigned i = 0;
  478. cell * c = r.m_ref;
  479. while (c->kind() != ROOT && i < trail_split_idx) {
  480. cs.push_back(c);
  481. c = c->next();
  482. i++;
  483. }
  484. if (c->kind() != ROOT) {
  485. // root is too far away.
  486. unfold(c);
  487. }
  488. SASSERT(c->kind() == ROOT);
  489. i = cs.size();
  490. while (i > 0) {
  491. --i;
  492. cell * p = cs[i];
  493. SASSERT(c->m_kind == ROOT);
  494. unsigned sz = c->m_size;
  495. value * vs = c->m_values;
  496. SASSERT(p->m_kind != ROOT);
  497. SASSERT(p->m_next == c);
  498. switch (p->m_kind) {
  499. case SET:
  500. c->m_kind = SET;
  501. c->m_idx = p->m_idx;
  502. c->m_elem = vs[c->m_idx];
  503. vs[p->m_idx] = p->m_elem;
  504. break;
  505. case PUSH_BACK:
  506. c->m_kind = POP_BACK;
  507. if (sz == capacity(vs))
  508. expand(vs);
  509. c->m_idx = sz;
  510. vs[sz] = p->m_elem;
  511. sz++;
  512. break;
  513. case POP_BACK:
  514. c->m_kind = PUSH_BACK;
  515. --sz;
  516. c->m_idx = sz;
  517. c->m_elem = vs[sz];
  518. break;
  519. case ROOT:
  520. UNREACHABLE();
  521. break;
  522. }
  523. inc_ref(p);
  524. c->m_next = p;
  525. // p does not point to c anymore
  526. dec_ref(c);
  527. p->m_kind = ROOT;
  528. p->m_size = sz;
  529. p->m_values = vs;
  530. c = p;
  531. }
  532. SASSERT(c == r.m_ref);
  533. SASSERT(c->kind() == ROOT);
  534. SASSERT(c->m_size == r_sz);
  535. r.m_updt_counter = 0;
  536. SASSERT(r.root());
  537. }
  538. void display_info(std::ostream & out, ref const & r) {
  539. cell * c = r.m_ref;
  540. if (c == 0) {
  541. out << "<null>";
  542. return;
  543. }
  544. while (true) {
  545. out << "cell[" << c << ", ";
  546. switch (c->kind()) {
  547. case SET: out << "set, " << c->m_idx; break;
  548. case PUSH_BACK: out << "push, " << c->m_idx; break;
  549. case POP_BACK: out << "pop, " << c->m_idx; break;
  550. case ROOT: out << "root, " << c->m_size << ", " << capacity(c->m_values); break;
  551. }
  552. out << "]#" << c->m_ref_count;
  553. if (c->kind() == ROOT)
  554. break;
  555. out << " -> ";
  556. c = c->next();
  557. }
  558. }
  559. };
  560. template<typename T>
  561. struct dummy_value_manager {
  562. void inc_ref(T const &) {}
  563. void dec_ref(T const &) {}
  564. };
  565. #endif