A C++ toolbox repo until the pair uTL/dTL arives
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

470 lines
14 KiB

  1. /*!
  2. * \file deque.cpp
  3. * \brief
  4. * Unit tests for deque
  5. *
  6. * \copyright Copyright (C) 2020 Christos Choutouridis <christos@choutouridis.net>
  7. *
  8. * <dl class=\"section copyright\"><dt>License</dt><dd>
  9. * The MIT License (MIT)
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in all
  19. * copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  27. * SOFTWARE.
  28. * </dd></dl>
  29. *
  30. */
  31. #include <cont/deque.h>
  32. #include <cont/span.h>
  33. #include <gtest/gtest.h>
  34. #include <array>
  35. #include <type_traits>
  36. #include <cstring>
  37. #ifndef WIN_TRHEADS
  38. #include <mutex>
  39. #include <thread>
  40. #else
  41. #include <mingw.thread.h>
  42. #include <mingw.mutex.h>
  43. #endif
  44. namespace Tdeque {
  45. using namespace tbx;
  46. template <typename>
  47. struct is_span : std::false_type {};
  48. template <typename T, std::size_t S>
  49. struct is_span<tbx::span<T, S>> : std::true_type {};
  50. template <typename>
  51. struct is_std_array : std::false_type {};
  52. template <typename T, std::size_t N>
  53. struct is_std_array<std::array<T, N>> : std::true_type {};
  54. template <typename, typename = void>
  55. struct has_size_and_data : std::false_type {};
  56. template <typename T>
  57. struct has_size_and_data<T, std::void_t<decltype(std::declval<T>().size()),
  58. decltype(std::declval<T>().data())>>
  59. : std::true_type {};
  60. // Concept
  61. TEST(Tdeque, concept) {
  62. using deque_t = deque<int, 8>;
  63. EXPECT_EQ ( std::is_default_constructible<deque_t>::value, true);
  64. EXPECT_EQ ( std::is_nothrow_default_constructible<deque_t>::value, true);
  65. EXPECT_EQ (!std::is_copy_constructible<deque_t>::value, true);
  66. EXPECT_EQ (!std::is_copy_assignable<deque_t>::value, true);
  67. EXPECT_EQ (true, !is_span<deque_t>::value);
  68. EXPECT_EQ (true, !is_std_array<deque_t>::value);
  69. EXPECT_EQ (true, !std::is_array<deque_t>::value);
  70. EXPECT_EQ (true, has_size_and_data<deque_t>::value);
  71. }
  72. // Test construction
  73. TEST(Tdeque, contruct) {
  74. deque<int, 8> q1;
  75. deque<int, 8> q2{1, 2, 3, 4, 5, 6, 7, 8};
  76. deque<int, 8> q3{1, 2, 3, 4, 5};
  77. EXPECT_EQ (8UL, q1.capacity());
  78. EXPECT_EQ (0UL, q1.size());
  79. EXPECT_EQ (8UL, q2.capacity());
  80. EXPECT_EQ (8UL, q2.size());
  81. EXPECT_EQ (8UL, q3.capacity());
  82. EXPECT_EQ (5UL, q3.size());
  83. }
  84. // simple push-pop functionality
  85. TEST(Tdeque, push_pop) {
  86. deque<int, 8> q1;
  87. deque<int, 8> q2{1, 2, 3, 4, 5, 6, 7, 8};
  88. q1.push_front(1);
  89. q1.push_front(2);
  90. EXPECT_EQ (1, q1.pop_back());
  91. EXPECT_EQ (2, q1.pop_back());
  92. q1.push_back(1);
  93. q1.push_back(2);
  94. EXPECT_EQ (1, q1.pop_front());
  95. EXPECT_EQ (2, q1.pop_front());
  96. q1.push_front(2);
  97. q1.push_back(3);
  98. q1.push_front(1);
  99. q1.push_back(4);
  100. for (int i=1 ; i<= 4 ; ++i)
  101. EXPECT_EQ ((int)i, q1.pop_front());
  102. }
  103. // front-back
  104. TEST(Tdeque, front_back) {
  105. deque<int, 8> q1;
  106. deque<int, 8> q2{1, 2, 3, 4, 5, 6, 7, 8};
  107. q1.push_front(2);
  108. q1.push_front(1);
  109. q1.push_back(3);
  110. q1.push_back(4);
  111. EXPECT_EQ (1, q1.front());
  112. EXPECT_EQ (4, q1.back());
  113. EXPECT_EQ (1, q2.front());
  114. EXPECT_EQ (8, q2.back());
  115. }
  116. // capacity
  117. TEST(Tdeque, capacity) {
  118. deque<int, 8> q1;
  119. deque<int, 8> q2{1, 2, 3, 4, 5, 6, 7, 8};
  120. q1.push_back(1);
  121. q1.clear();
  122. EXPECT_EQ (true, q1.empty());
  123. EXPECT_EQ (true, q2.full());
  124. EXPECT_EQ (8UL, q1.capacity());
  125. EXPECT_EQ (8UL, q2.capacity());
  126. EXPECT_EQ (0UL, q1.size());
  127. EXPECT_EQ (8UL, q2.size());
  128. q1.push_back(2);
  129. EXPECT_EQ (1UL, q1.size());
  130. q1.push_front(1);
  131. EXPECT_EQ (2UL, q1.size());
  132. q1.pop_back();
  133. EXPECT_EQ (1UL, q1.size());
  134. q1.pop_front();
  135. EXPECT_EQ (0UL, q1.size());
  136. }
  137. // push-pop limits
  138. TEST (Tdeque, push_pop_limits) {
  139. deque<int, 8> q1;
  140. deque<int, 8> q2{1, 2, 3, 4, 5, 6, 7, 8};
  141. EXPECT_EQ (int{}, q1.pop_back());
  142. EXPECT_EQ (0UL, q1.size());
  143. EXPECT_EQ (true, q1.empty());
  144. EXPECT_EQ (false, q1.full());
  145. EXPECT_EQ (int{}, q1.pop_front());
  146. EXPECT_EQ (0UL, q1.size());
  147. EXPECT_EQ (true, q1.empty());
  148. EXPECT_EQ (false, q1.full());
  149. q2.push_front(0);
  150. EXPECT_EQ (1, q2.front());
  151. EXPECT_EQ (8, q2.back());
  152. EXPECT_EQ (8UL, q2.size());
  153. EXPECT_EQ (false, q2.empty());
  154. EXPECT_EQ (true, q2.full());
  155. q2.push_back(9);
  156. EXPECT_EQ (1, q2.front());
  157. EXPECT_EQ (8, q2.back());
  158. EXPECT_EQ (8UL, q2.size());
  159. EXPECT_EQ (false, q2.empty());
  160. EXPECT_EQ (true, q2.full());
  161. }
  162. // iterators
  163. TEST (Tdeque, iterators) {
  164. deque<int, 8> q1{1, 2, 3, 4, 5, 6, 7, 8};
  165. int check_it=1;
  166. EXPECT_EQ (q1.begin().base(), q1.end().base());
  167. EXPECT_NE (q1.begin().iter(), q1.end().iter());
  168. EXPECT_EQ (1, *q1.begin());
  169. EXPECT_EQ (true, (q1.begin() == ++q1.end())); // loop edge iterators
  170. for (auto it = q1.begin() ; it != q1.end() ; ++it)
  171. EXPECT_EQ(*it, check_it++);
  172. EXPECT_EQ(9, check_it); // run through all
  173. EXPECT_EQ (1, q1.front()); // queue stays intact
  174. EXPECT_EQ (8, q1.back());
  175. EXPECT_EQ (8UL, q1.size());
  176. EXPECT_EQ (false, q1.empty());
  177. EXPECT_EQ (true, q1.full());
  178. q1.pop_front();
  179. q1.pop_back();
  180. check_it=2;
  181. for (auto& it : q1)
  182. EXPECT_EQ(it, check_it++);
  183. EXPECT_EQ(8, check_it); // run through all
  184. EXPECT_EQ (2, q1.front()); // queue stays intact
  185. EXPECT_EQ (7, q1.back());
  186. EXPECT_EQ (6UL, q1.size());
  187. EXPECT_EQ (false, q1.empty());
  188. EXPECT_EQ (false, q1.full());
  189. deque<int, 8> q2;
  190. q2.push_front(2);
  191. q2.push_front(1);
  192. q2.push_back(3);
  193. q2.push_back(4);
  194. q2.push_back(5);
  195. check_it =1;
  196. for (auto& it : q2)
  197. EXPECT_EQ(it, check_it++);
  198. EXPECT_EQ(6, check_it); // run through all
  199. }
  200. TEST (Tdeque, range) {
  201. deque<int, 8> q1{1, 2, 3, 4, 5, 6, 7, 8};
  202. int check_it=1;
  203. for (auto& it : q1.contents())
  204. EXPECT_EQ(it, check_it++);
  205. EXPECT_EQ(9, check_it); // run through all
  206. }
  207. // Concept
  208. TEST(Tdeque, concept_atomic) {
  209. using deque_t = deque<int, 8, true>;
  210. EXPECT_EQ (true, !is_span<deque_t>::value);
  211. EXPECT_EQ (true, !is_std_array<deque_t>::value);
  212. EXPECT_EQ (true, !std::is_array<deque_t>::value);
  213. EXPECT_EQ (true, has_size_and_data<deque_t>::value);
  214. }
  215. // Test construction
  216. TEST(Tdeque, contruct_atomic) {
  217. deque<int, 8, true> q1;
  218. deque<int, 8, true> q2{1, 2, 3, 4, 5, 6, 7, 8};
  219. deque<int, 8, true> q3{1, 2, 3, 4, 5};
  220. EXPECT_EQ (8UL, q1.capacity());
  221. EXPECT_EQ (0UL, q1.size());
  222. EXPECT_EQ (8UL, q2.capacity());
  223. EXPECT_EQ (8UL, q2.size());
  224. EXPECT_EQ (8UL, q3.capacity());
  225. EXPECT_EQ (5UL, q3.size());
  226. }
  227. // simple push-pop functionality
  228. TEST(Tdeque, push_pop_atomic) {
  229. deque<int, 8, true> q1;
  230. deque<int, 8, true> q2{1, 2, 3, 4, 5, 6, 7, 8};
  231. q1.push_front(1);
  232. q1.push_front(2);
  233. EXPECT_EQ (1, q1.pop_back());
  234. EXPECT_EQ (2, q1.pop_back());
  235. q1.push_back(1);
  236. q1.push_back(2);
  237. EXPECT_EQ (1, q1.pop_front());
  238. EXPECT_EQ (2, q1.pop_front());
  239. q1.push_front(2);
  240. q1.push_back(3);
  241. q1.push_front(1);
  242. q1.push_back(4);
  243. for (int i=1 ; i<= 4 ; ++i)
  244. EXPECT_EQ ((int)i, q1.pop_front());
  245. }
  246. // front-back
  247. TEST(Tdeque, front_back_atomic) {
  248. deque<int, 8, true> q1;
  249. deque<int, 8, true> q2{1, 2, 3, 4, 5, 6, 7, 8};
  250. q1.push_front(2);
  251. q1.push_front(1);
  252. q1.push_back(3);
  253. q1.push_back(4);
  254. EXPECT_EQ (1, q1.front());
  255. EXPECT_EQ (4, q1.back());
  256. EXPECT_EQ (1, q2.front());
  257. EXPECT_EQ (8, q2.back());
  258. }
  259. // capacity
  260. TEST(Tdeque, capacity_atomic) {
  261. deque<int, 8, true> q1;
  262. deque<int, 8, true> q2{1, 2, 3, 4, 5, 6, 7, 8};
  263. q1.push_back(1);
  264. q1.clear();
  265. EXPECT_EQ (true, q1.empty());
  266. EXPECT_EQ (true, q2.full());
  267. EXPECT_EQ (8UL, q1.capacity());
  268. EXPECT_EQ (8UL, q2.capacity());
  269. EXPECT_EQ (0UL, q1.size());
  270. EXPECT_EQ (8UL, q2.size());
  271. q1.push_back(2);
  272. EXPECT_EQ (1UL, q1.size());
  273. q1.push_front(1);
  274. EXPECT_EQ (2UL, q1.size());
  275. q1.pop_back();
  276. EXPECT_EQ (1UL, q1.size());
  277. q1.pop_front();
  278. EXPECT_EQ (0UL, q1.size());
  279. }
  280. // push-pop limits
  281. TEST (Tdeque, push_pop_limits_atomic) {
  282. deque<int, 8, true> q1;
  283. deque<int, 8, true> q2{1, 2, 3, 4, 5, 6, 7, 8};
  284. EXPECT_EQ (int{}, q1.pop_back());
  285. EXPECT_EQ (0UL, q1.size());
  286. EXPECT_EQ (true, q1.empty());
  287. EXPECT_EQ (false, q1.full());
  288. EXPECT_EQ (int{}, q1.pop_front());
  289. EXPECT_EQ (0UL, q1.size());
  290. EXPECT_EQ (true, q1.empty());
  291. EXPECT_EQ (false, q1.full());
  292. q2.push_front(0);
  293. EXPECT_EQ (1, q2.front());
  294. EXPECT_EQ (8, q2.back());
  295. EXPECT_EQ (8UL, q2.size());
  296. EXPECT_EQ (false, q2.empty());
  297. EXPECT_EQ (true, q2.full());
  298. q2.push_back(9);
  299. EXPECT_EQ (1, q2.front());
  300. EXPECT_EQ (8, q2.back());
  301. EXPECT_EQ (8UL, q2.size());
  302. EXPECT_EQ (false, q2.empty());
  303. EXPECT_EQ (true, q2.full());
  304. }
  305. // iterators
  306. TEST (Tdeque, iterators_atomic) {
  307. deque<int, 8, true> q1{1, 2, 3, 4, 5, 6, 7, 8};
  308. int check_it=1;
  309. EXPECT_EQ (q1.begin().base(), q1.end().base());
  310. EXPECT_NE (q1.begin().iter(), q1.end().iter());
  311. EXPECT_EQ (1, *q1.begin());
  312. EXPECT_EQ (true, (q1.begin() == ++q1.end())); // loop edge iterators
  313. for (auto it = q1.begin() ; it != q1.end() ; ++it)
  314. EXPECT_EQ(*it, check_it++);
  315. EXPECT_EQ(9, check_it); // run through all
  316. EXPECT_EQ (1, q1.front()); // queue stays intact
  317. EXPECT_EQ (8, q1.back());
  318. EXPECT_EQ (8UL, q1.size());
  319. EXPECT_EQ (false, q1.empty());
  320. EXPECT_EQ (true, q1.full());
  321. q1.pop_front();
  322. q1.pop_back();
  323. check_it=2;
  324. for (auto& it : q1)
  325. EXPECT_EQ(it, check_it++);
  326. EXPECT_EQ(8, check_it); // run through all
  327. EXPECT_EQ (2, q1.front()); // queue stays intact
  328. EXPECT_EQ (7, q1.back());
  329. EXPECT_EQ (6UL, q1.size());
  330. EXPECT_EQ (false, q1.empty());
  331. EXPECT_EQ (false, q1.full());
  332. deque<int, 8, true> q2;
  333. q2.push_front(2);
  334. q2.push_front(1);
  335. q2.push_back(3);
  336. q2.push_back(4);
  337. q2.push_back(5);
  338. check_it =1;
  339. for (auto& it : q2)
  340. EXPECT_EQ(it, check_it++);
  341. EXPECT_EQ(6, check_it); // run through all
  342. }
  343. TEST (Tdeque, range_atomic) {
  344. deque<int, 8, true> q1{1, 2, 3, 4, 5, 6, 7, 8};
  345. int check_it=1;
  346. for (auto& it : q1.contents())
  347. EXPECT_EQ(it, check_it++);
  348. EXPECT_EQ(9, check_it); // run through all
  349. }
  350. TEST(Tdeque, race) {
  351. constexpr size_t N = 1000000;
  352. deque<int, N, true> q;
  353. int result[N];
  354. auto push_front = [&](){
  355. for (size_t i=1 ; i<=N ; ++i) q.push_front(i);
  356. };
  357. auto push_back = [&](){
  358. for (size_t i=1 ; i<=N ; ++i) q.push_back(i);
  359. };
  360. auto pop_front = [&](){
  361. for (size_t i=0 ; i<N ; ) {
  362. result[i] = q.pop_front();
  363. if (result[i] != int{})
  364. ++i;
  365. }
  366. };
  367. auto pop_back = [&](){
  368. for (size_t i=0 ; i<N ; ) {
  369. result[i] = q.pop_back();
  370. if (result[i] != int{})
  371. ++i;
  372. }
  373. };
  374. std::memset(result, 0, sizeof result);
  375. std::thread th1 (push_front);
  376. std::thread th2 (pop_back);
  377. th1.join();
  378. th2.join();
  379. for (size_t i=0 ; i<N ; ++i)
  380. EXPECT_EQ (result[i], (int)i+1);
  381. std::memset(result, 0, sizeof result);
  382. std::thread th3 (push_back);
  383. std::thread th4 (pop_front);
  384. th3.join();
  385. th4.join();
  386. for (size_t i=0 ; i<N ; ++i)
  387. EXPECT_EQ (result[i], (int)i+1);
  388. }
  389. }