test.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. // Copyright 2006-2009 Daniel James.
  2. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  3. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  4. #if !defined(BOOST_UNORDERED_TEST_OBJECTS_HEADER)
  5. #define BOOST_UNORDERED_TEST_OBJECTS_HEADER
  6. #include "../helpers/count.hpp"
  7. #include "../helpers/fwd.hpp"
  8. #include "../helpers/memory.hpp"
  9. #include <boost/config.hpp>
  10. #include <boost/limits.hpp>
  11. #include <cstddef>
  12. namespace test {
  13. // Note that the default hash function will work for any equal_to (but not
  14. // very well).
  15. class object;
  16. class movable;
  17. class implicitly_convertible;
  18. class hash;
  19. class less;
  20. class equal_to;
  21. template <class T> class allocator1;
  22. template <class T> class allocator2;
  23. object generate(object const*, random_generator);
  24. movable generate(movable const*, random_generator);
  25. implicitly_convertible generate(
  26. implicitly_convertible const*, random_generator);
  27. inline void ignore_variable(void const*) {}
  28. class object : private counted_object
  29. {
  30. friend class hash;
  31. friend class equal_to;
  32. friend class less;
  33. int tag1_, tag2_;
  34. public:
  35. explicit object(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {}
  36. ~object()
  37. {
  38. tag1_ = -1;
  39. tag2_ = -1;
  40. }
  41. friend bool operator==(object const& x1, object const& x2)
  42. {
  43. return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
  44. }
  45. friend bool operator!=(object const& x1, object const& x2)
  46. {
  47. return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_;
  48. }
  49. friend bool operator<(object const& x1, object const& x2)
  50. {
  51. return x1.tag1_ < x2.tag1_ ||
  52. (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
  53. }
  54. friend object generate(object const*, random_generator g)
  55. {
  56. int* x = 0;
  57. return object(generate(x, g), generate(x, g));
  58. }
  59. friend std::ostream& operator<<(std::ostream& out, object const& o)
  60. {
  61. return out << "(" << o.tag1_ << "," << o.tag2_ << ")";
  62. }
  63. };
  64. class movable : private counted_object
  65. {
  66. friend class hash;
  67. friend class equal_to;
  68. friend class less;
  69. int tag1_, tag2_;
  70. BOOST_COPYABLE_AND_MOVABLE(movable)
  71. public:
  72. explicit movable(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {}
  73. movable(movable const& x)
  74. : counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_)
  75. {
  76. BOOST_TEST(x.tag1_ != -1);
  77. }
  78. movable(BOOST_RV_REF(movable) x)
  79. : counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_)
  80. {
  81. BOOST_TEST(x.tag1_ != -1);
  82. x.tag1_ = -1;
  83. x.tag2_ = -1;
  84. }
  85. movable& operator=(BOOST_COPY_ASSIGN_REF(movable) x) // Copy assignment
  86. {
  87. BOOST_TEST(x.tag1_ != -1);
  88. tag1_ = x.tag1_;
  89. tag2_ = x.tag2_;
  90. return *this;
  91. }
  92. movable& operator=(BOOST_RV_REF(movable) x) // Move assignment
  93. {
  94. BOOST_TEST(x.tag1_ != -1);
  95. tag1_ = x.tag1_;
  96. tag2_ = x.tag2_;
  97. x.tag1_ = -1;
  98. x.tag2_ = -1;
  99. return *this;
  100. }
  101. ~movable()
  102. {
  103. tag1_ = -1;
  104. tag2_ = -1;
  105. }
  106. friend bool operator==(movable const& x1, movable const& x2)
  107. {
  108. BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
  109. return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
  110. }
  111. friend bool operator!=(movable const& x1, movable const& x2)
  112. {
  113. BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
  114. return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_;
  115. }
  116. friend bool operator<(movable const& x1, movable const& x2)
  117. {
  118. BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
  119. return x1.tag1_ < x2.tag1_ ||
  120. (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
  121. }
  122. friend movable generate(movable const*, random_generator g)
  123. {
  124. int* x = 0;
  125. return movable(generate(x, g), generate(x, g));
  126. }
  127. friend std::ostream& operator<<(std::ostream& out, movable const& o)
  128. {
  129. return out << "(" << o.tag1_ << "," << o.tag2_ << ")";
  130. }
  131. };
  132. class implicitly_convertible : private counted_object
  133. {
  134. int tag1_, tag2_;
  135. public:
  136. explicit implicitly_convertible(int t1 = 0, int t2 = 0)
  137. : tag1_(t1), tag2_(t2)
  138. {
  139. }
  140. operator object() const { return object(tag1_, tag2_); }
  141. operator movable() const { return movable(tag1_, tag2_); }
  142. friend implicitly_convertible generate(
  143. implicitly_convertible const*, random_generator g)
  144. {
  145. int* x = 0;
  146. return implicitly_convertible(generate(x, g), generate(x, g));
  147. }
  148. friend std::ostream& operator<<(
  149. std::ostream& out, implicitly_convertible const& o)
  150. {
  151. return out << "(" << o.tag1_ << "," << o.tag2_ << ")";
  152. }
  153. };
  154. // Note: This is a deliberately bad hash function.
  155. class hash
  156. {
  157. int type_;
  158. public:
  159. hash() : type_(0) {}
  160. explicit hash(int t) : type_(t) {}
  161. std::size_t operator()(object const& x) const
  162. {
  163. int result;
  164. switch (type_) {
  165. case 1:
  166. result = x.tag1_;
  167. break;
  168. case 2:
  169. result = x.tag2_;
  170. break;
  171. default:
  172. result = x.tag1_ + x.tag2_;
  173. }
  174. return static_cast<std::size_t>(result);
  175. }
  176. std::size_t operator()(movable const& x) const
  177. {
  178. int result;
  179. switch (type_) {
  180. case 1:
  181. result = x.tag1_;
  182. break;
  183. case 2:
  184. result = x.tag2_;
  185. break;
  186. default:
  187. result = x.tag1_ + x.tag2_;
  188. }
  189. return static_cast<std::size_t>(result);
  190. }
  191. std::size_t operator()(int x) const
  192. {
  193. int result;
  194. switch (type_) {
  195. case 1:
  196. result = x;
  197. break;
  198. case 2:
  199. result = x * 7;
  200. break;
  201. default:
  202. result = x * 256;
  203. }
  204. return static_cast<std::size_t>(result);
  205. }
  206. friend bool operator==(hash const& x1, hash const& x2)
  207. {
  208. return x1.type_ == x2.type_;
  209. }
  210. friend bool operator!=(hash const& x1, hash const& x2)
  211. {
  212. return x1.type_ != x2.type_;
  213. }
  214. };
  215. std::size_t hash_value(test::object const& x) { return hash()(x); }
  216. std::size_t hash_value(test::movable const& x) { return hash()(x); }
  217. class less
  218. {
  219. int type_;
  220. public:
  221. explicit less(int t = 0) : type_(t) {}
  222. bool operator()(object const& x1, object const& x2) const
  223. {
  224. switch (type_) {
  225. case 1:
  226. return x1.tag1_ < x2.tag1_;
  227. case 2:
  228. return x1.tag2_ < x2.tag2_;
  229. default:
  230. return x1 < x2;
  231. }
  232. }
  233. bool operator()(movable const& x1, movable const& x2) const
  234. {
  235. switch (type_) {
  236. case 1:
  237. return x1.tag1_ < x2.tag1_;
  238. case 2:
  239. return x1.tag2_ < x2.tag2_;
  240. default:
  241. return x1 < x2;
  242. }
  243. }
  244. std::size_t operator()(int x1, int x2) const { return x1 < x2; }
  245. friend bool operator==(less const& x1, less const& x2)
  246. {
  247. return x1.type_ == x2.type_;
  248. }
  249. };
  250. class equal_to
  251. {
  252. int type_;
  253. public:
  254. equal_to() : type_(0) {}
  255. explicit equal_to(int t) : type_(t) {}
  256. bool operator()(object const& x1, object const& x2) const
  257. {
  258. switch (type_) {
  259. case 1:
  260. return x1.tag1_ == x2.tag1_;
  261. case 2:
  262. return x1.tag2_ == x2.tag2_;
  263. default:
  264. return x1 == x2;
  265. }
  266. }
  267. bool operator()(movable const& x1, movable const& x2) const
  268. {
  269. switch (type_) {
  270. case 1:
  271. return x1.tag1_ == x2.tag1_;
  272. case 2:
  273. return x1.tag2_ == x2.tag2_;
  274. default:
  275. return x1 == x2;
  276. }
  277. }
  278. std::size_t operator()(int x1, int x2) const { return x1 == x2; }
  279. friend bool operator==(equal_to const& x1, equal_to const& x2)
  280. {
  281. return x1.type_ == x2.type_;
  282. }
  283. friend bool operator!=(equal_to const& x1, equal_to const& x2)
  284. {
  285. return x1.type_ != x2.type_;
  286. }
  287. friend less create_compare(equal_to x) { return less(x.type_); }
  288. };
  289. // allocator1 only has the old fashioned 'construct' method and has
  290. // a few less typedefs. allocator2 uses a custom pointer class.
  291. template <class T> class allocator1
  292. {
  293. public:
  294. int tag_;
  295. typedef T value_type;
  296. template <class U> struct rebind
  297. {
  298. typedef allocator1<U> other;
  299. };
  300. allocator1() : tag_(0) { detail::tracker.allocator_ref(); }
  301. explicit allocator1(int t) : tag_(t) { detail::tracker.allocator_ref(); }
  302. template <class Y> allocator1(allocator1<Y> const& x) : tag_(x.tag_)
  303. {
  304. detail::tracker.allocator_ref();
  305. }
  306. allocator1(allocator1 const& x) : tag_(x.tag_)
  307. {
  308. detail::tracker.allocator_ref();
  309. }
  310. ~allocator1() { detail::tracker.allocator_unref(); }
  311. T* allocate(std::size_t n)
  312. {
  313. T* ptr(static_cast<T*>(::operator new(n * sizeof(T))));
  314. detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_);
  315. return ptr;
  316. }
  317. T* allocate(std::size_t n, void const*)
  318. {
  319. T* ptr(static_cast<T*>(::operator new(n * sizeof(T))));
  320. detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_);
  321. return ptr;
  322. }
  323. void deallocate(T* p, std::size_t n)
  324. {
  325. detail::tracker.track_deallocate((void*)p, n, sizeof(T), tag_);
  326. ::operator delete((void*)p);
  327. }
  328. #if BOOST_UNORDERED_CXX11_CONSTRUCTION
  329. template <typename U, typename... Args> void construct(U* p, Args&&... args)
  330. {
  331. detail::tracker.track_construct((void*)p, sizeof(U), tag_);
  332. new (p) U(boost::forward<Args>(args)...);
  333. }
  334. template <typename U> void destroy(U* p)
  335. {
  336. detail::tracker.track_destroy((void*)p, sizeof(U), tag_);
  337. p->~U();
  338. // Work around MSVC buggy unused parameter warning.
  339. ignore_variable(&p);
  340. }
  341. #else
  342. private:
  343. // I'm going to claim in the documentation that construct/destroy
  344. // is never used when C++11 support isn't available, so might as
  345. // well check that in the text.
  346. // TODO: Or maybe just disallow them for values?
  347. template <typename U> void construct(U* p);
  348. template <typename U, typename A0> void construct(U* p, A0 const&);
  349. template <typename U, typename A0, typename A1>
  350. void construct(U* p, A0 const&, A1 const&);
  351. template <typename U, typename A0, typename A1, typename A2>
  352. void construct(U* p, A0 const&, A1 const&, A2 const&);
  353. template <typename U> void destroy(U* p);
  354. public:
  355. #endif
  356. bool operator==(allocator1 const& x) const { return tag_ == x.tag_; }
  357. bool operator!=(allocator1 const& x) const { return tag_ != x.tag_; }
  358. enum
  359. {
  360. is_select_on_copy = false,
  361. is_propagate_on_swap = false,
  362. is_propagate_on_assign = false,
  363. is_propagate_on_move = false
  364. };
  365. };
  366. template <class T> class ptr;
  367. template <class T> class const_ptr;
  368. struct void_ptr
  369. {
  370. #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
  371. template <typename T> friend class ptr;
  372. private:
  373. #endif
  374. void* ptr_;
  375. public:
  376. void_ptr() : ptr_(0) {}
  377. template <typename T> explicit void_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
  378. // I'm not using the safe bool idiom because the containers should be
  379. // able to cope with bool conversions.
  380. operator bool() const { return !!ptr_; }
  381. bool operator==(void_ptr const& x) const { return ptr_ == x.ptr_; }
  382. bool operator!=(void_ptr const& x) const { return ptr_ != x.ptr_; }
  383. };
  384. class void_const_ptr
  385. {
  386. #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
  387. template <typename T> friend class const_ptr;
  388. private:
  389. #endif
  390. void* ptr_;
  391. public:
  392. void_const_ptr() : ptr_(0) {}
  393. template <typename T>
  394. explicit void_const_ptr(const_ptr<T> const& x) : ptr_(x.ptr_)
  395. {
  396. }
  397. // I'm not using the safe bool idiom because the containers should be
  398. // able to cope with bool conversions.
  399. operator bool() const { return !!ptr_; }
  400. bool operator==(void_const_ptr const& x) const { return ptr_ == x.ptr_; }
  401. bool operator!=(void_const_ptr const& x) const { return ptr_ != x.ptr_; }
  402. };
  403. template <class T> class ptr
  404. {
  405. friend class allocator2<T>;
  406. friend class const_ptr<T>;
  407. friend struct void_ptr;
  408. T* ptr_;
  409. ptr(T* x) : ptr_(x) {}
  410. public:
  411. ptr() : ptr_(0) {}
  412. explicit ptr(void_ptr const& x) : ptr_((T*)x.ptr_) {}
  413. T& operator*() const { return *ptr_; }
  414. T* operator->() const { return ptr_; }
  415. ptr& operator++()
  416. {
  417. ++ptr_;
  418. return *this;
  419. }
  420. ptr operator++(int)
  421. {
  422. ptr tmp(*this);
  423. ++ptr_;
  424. return tmp;
  425. }
  426. ptr operator+(std::ptrdiff_t s) const { return ptr<T>(ptr_ + s); }
  427. friend ptr operator+(std::ptrdiff_t s, ptr p) { return ptr<T>(s + p.ptr_); }
  428. T& operator[](std::ptrdiff_t s) const { return ptr_[s]; }
  429. bool operator!() const { return !ptr_; }
  430. // I'm not using the safe bool idiom because the containers should be
  431. // able to cope with bool conversions.
  432. operator bool() const { return !!ptr_; }
  433. bool operator==(ptr const& x) const { return ptr_ == x.ptr_; }
  434. bool operator!=(ptr const& x) const { return ptr_ != x.ptr_; }
  435. bool operator<(ptr const& x) const { return ptr_ < x.ptr_; }
  436. bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
  437. bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
  438. bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
  439. };
  440. template <class T> class const_ptr
  441. {
  442. friend class allocator2<T>;
  443. friend struct const_void_ptr;
  444. T const* ptr_;
  445. const_ptr(T const* ptr) : ptr_(ptr) {}
  446. public:
  447. const_ptr() : ptr_(0) {}
  448. const_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
  449. explicit const_ptr(void_const_ptr const& x) : ptr_((T const*)x.ptr_) {}
  450. T const& operator*() const { return *ptr_; }
  451. T const* operator->() const { return ptr_; }
  452. const_ptr& operator++()
  453. {
  454. ++ptr_;
  455. return *this;
  456. }
  457. const_ptr operator++(int)
  458. {
  459. const_ptr tmp(*this);
  460. ++ptr_;
  461. return tmp;
  462. }
  463. const_ptr operator+(std::ptrdiff_t s) const { return const_ptr(ptr_ + s); }
  464. friend const_ptr operator+(std::ptrdiff_t s, const_ptr p)
  465. {
  466. return ptr<T>(s + p.ptr_);
  467. }
  468. T const& operator[](int s) const { return ptr_[s]; }
  469. bool operator!() const { return !ptr_; }
  470. operator bool() const { return !!ptr_; }
  471. bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; }
  472. bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; }
  473. bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; }
  474. bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; }
  475. bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; }
  476. bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; }
  477. };
  478. template <class T> class allocator2
  479. {
  480. #ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
  481. public:
  482. #else
  483. template <class> friend class allocator2;
  484. #endif
  485. int tag_;
  486. public:
  487. typedef std::size_t size_type;
  488. typedef std::ptrdiff_t difference_type;
  489. typedef void_ptr void_pointer;
  490. typedef void_const_ptr const_void_pointer;
  491. typedef ptr<T> pointer;
  492. typedef const_ptr<T> const_pointer;
  493. typedef T& reference;
  494. typedef T const& const_reference;
  495. typedef T value_type;
  496. template <class U> struct rebind
  497. {
  498. typedef allocator2<U> other;
  499. };
  500. allocator2() : tag_(0) { detail::tracker.allocator_ref(); }
  501. explicit allocator2(int t) : tag_(t) { detail::tracker.allocator_ref(); }
  502. template <class Y> allocator2(allocator2<Y> const& x) : tag_(x.tag_)
  503. {
  504. detail::tracker.allocator_ref();
  505. }
  506. allocator2(allocator2 const& x) : tag_(x.tag_)
  507. {
  508. detail::tracker.allocator_ref();
  509. }
  510. ~allocator2() { detail::tracker.allocator_unref(); }
  511. pointer address(reference r) { return pointer(&r); }
  512. const_pointer address(const_reference r) { return const_pointer(&r); }
  513. pointer allocate(size_type n)
  514. {
  515. pointer p(static_cast<T*>(::operator new(n * sizeof(T))));
  516. detail::tracker.track_allocate((void*)p.ptr_, n, sizeof(T), tag_);
  517. return p;
  518. }
  519. pointer allocate(size_type n, void const*)
  520. {
  521. pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
  522. detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_);
  523. return ptr;
  524. }
  525. void deallocate(pointer p, size_type n)
  526. {
  527. detail::tracker.track_deallocate((void*)p.ptr_, n, sizeof(T), tag_);
  528. ::operator delete((void*)p.ptr_);
  529. }
  530. void construct(T* p, T const& t)
  531. {
  532. detail::tracker.track_construct((void*)p, sizeof(T), tag_);
  533. new (p) T(t);
  534. }
  535. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  536. template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args)
  537. {
  538. detail::tracker.track_construct((void*)p, sizeof(T), tag_);
  539. new (p) T(boost::forward<Args>(args)...);
  540. }
  541. #endif
  542. void destroy(T* p)
  543. {
  544. detail::tracker.track_destroy((void*)p, sizeof(T), tag_);
  545. p->~T();
  546. }
  547. size_type max_size() const
  548. {
  549. return (std::numeric_limits<size_type>::max)();
  550. }
  551. bool operator==(allocator2 const& x) const { return tag_ == x.tag_; }
  552. bool operator!=(allocator2 const& x) const { return tag_ != x.tag_; }
  553. enum
  554. {
  555. is_select_on_copy = false,
  556. is_propagate_on_swap = false,
  557. is_propagate_on_assign = false,
  558. is_propagate_on_move = false
  559. };
  560. };
  561. template <class T>
  562. bool equivalent_impl(
  563. allocator1<T> const& x, allocator1<T> const& y, test::derived_type)
  564. {
  565. return x == y;
  566. }
  567. template <class T>
  568. bool equivalent_impl(
  569. allocator2<T> const& x, allocator2<T> const& y, test::derived_type)
  570. {
  571. return x == y;
  572. }
  573. }
  574. #endif