1 /* Self tests for array_view for GDB, the GNU debugger. 2 3 Copyright (C) 2017-2020 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "defs.h" 21 #include "gdbsupport/selftest.h" 22 #include "gdbsupport/array-view.h" 23 #include <array> 24 25 namespace selftests { 26 namespace array_view_tests { 27 28 /* Triviality checks. */ 29 #define CHECK_TRAIT(TRAIT) \ 30 static_assert (std::TRAIT<gdb::array_view<gdb_byte>>::value, "") 31 32 #if HAVE_IS_TRIVIALLY_COPYABLE 33 34 CHECK_TRAIT (is_trivially_copyable); 35 CHECK_TRAIT (is_trivially_move_assignable); 36 CHECK_TRAIT (is_trivially_move_constructible); 37 CHECK_TRAIT (is_trivially_destructible); 38 39 #endif 40 41 #undef CHECK_TRAIT 42 43 /* Wrapper around std::is_convertible to make the code using it a bit 44 shorter. (With C++14 we'd use a variable template instead.) */ 45 46 template<typename From, typename To> 47 static constexpr bool 48 is_convertible () 49 { 50 return std::is_convertible<From, To>::value; 51 } 52 53 /* Check for implicit conversion to immutable and mutable views. */ 54 55 static constexpr bool 56 check_convertible () 57 { 58 using T = gdb_byte; 59 using gdb::array_view; 60 61 return (true 62 /* immutable array_view */ 63 && is_convertible<const T (&) [1], array_view<const T>> () 64 && is_convertible<T (&) [1], array_view<const T>> () 65 && is_convertible<const T, array_view<const T>> () 66 && is_convertible<T, array_view<const T>> () 67 68 /* mutable array_view */ 69 && is_convertible<T (&) [1], array_view<T>> () 70 && !is_convertible<const T (&) [1], array_view<T>> () 71 && is_convertible<T, array_view<T>> () 72 && !is_convertible<const T, array_view<T>> () 73 74 /* While float is implicitly convertible to gdb_byte, we 75 don't want implicit float->array_view<gdb_byte> 76 conversion. */ 77 && !is_convertible<float, array_view<const T>> () 78 && !is_convertible<float, array_view<T>> ()); 79 } 80 81 static_assert (check_convertible (), ""); 82 83 namespace no_slicing 84 { 85 struct A { int i; }; 86 struct B : A { int j; }; 87 struct C : A { int l; }; 88 89 /* Check that there's no array->view conversion for arrays of derived 90 types or subclasses. */ 91 static constexpr bool 92 check () 93 { 94 using gdb::array_view; 95 96 return (true 97 98 /* array->view */ 99 100 && is_convertible <A (&)[1], array_view<A>> () 101 && !is_convertible <B (&)[1], array_view<A>> () 102 && !is_convertible <C (&)[1], array_view<A>> () 103 104 && !is_convertible <A (&)[1], array_view<B>> () 105 && is_convertible <B (&)[1], array_view<B>> () 106 && !is_convertible <C (&)[1], array_view<B>> () 107 108 /* elem->view */ 109 110 && is_convertible <A, array_view<A>> () 111 && !is_convertible <B, array_view<A>> () 112 && !is_convertible <C, array_view<A>> () 113 114 && !is_convertible <A, array_view<B>> () 115 && is_convertible <B, array_view<B>> () 116 && !is_convertible <C, array_view<B>> ()); 117 } 118 119 } /* namespace no_slicing */ 120 121 static_assert (no_slicing::check (), ""); 122 123 /* Check that array_view implicitly converts from std::vector. */ 124 125 static constexpr bool 126 check_convertible_from_std_vector () 127 { 128 using gdb::array_view; 129 using T = gdb_byte; 130 131 /* Note there's no such thing as std::vector<const T>. */ 132 133 return (true 134 && is_convertible <std::vector<T>, array_view<T>> () 135 && is_convertible <std::vector<T>, array_view<const T>> ()); 136 } 137 138 static_assert (check_convertible_from_std_vector (), ""); 139 140 /* Check that array_view implicitly converts from std::array. */ 141 142 static constexpr bool 143 check_convertible_from_std_array () 144 { 145 using gdb::array_view; 146 using T = gdb_byte; 147 148 /* Note: a non-const T view can't refer to a const T array. */ 149 150 return (true 151 && is_convertible <std::array<T, 1>, array_view<T>> () 152 && is_convertible <std::array<T, 1>, array_view<const T>> () 153 && !is_convertible <std::array<const T, 1>, array_view<T>> () 154 && is_convertible <std::array<const T, 1>, array_view<const T>> ()); 155 } 156 157 static_assert (check_convertible_from_std_array (), ""); 158 159 /* Check that VIEW views C (a container like std::vector/std::array) 160 correctly. */ 161 162 template<typename View, typename Container> 163 static bool 164 check_container_view (const View &view, const Container &c) 165 { 166 if (view.empty ()) 167 return false; 168 if (view.size () != c.size ()) 169 return false; 170 if (view.data () != c.data ()) 171 return false; 172 for (size_t i = 0; i < c.size (); i++) 173 { 174 if (&view[i] != &c[i]) 175 return false; 176 if (view[i] != c[i]) 177 return false; 178 } 179 return true; 180 } 181 182 /* Check that VIEW views E (an object of the type of a view element) 183 correctly. */ 184 185 template<typename View, typename Elem> 186 static bool 187 check_elem_view (const View &view, const Elem &e) 188 { 189 if (view.empty ()) 190 return false; 191 if (view.size () != 1) 192 return false; 193 if (view.data () != &e) 194 return false; 195 if (&view[0] != &e) 196 return false; 197 if (view[0] != e) 198 return false; 199 return true; 200 } 201 202 /* Check for operator[]. The first overload is taken iff 203 'view<T>()[0] = T()' is a valid expression. */ 204 205 template<typename View, 206 typename = decltype (std::declval<View> ()[0] 207 = std::declval<typename View::value_type> ())> 208 static bool 209 check_op_subscript (const View &view) 210 { 211 return true; 212 } 213 214 /* This overload is taken iff 'view<T>()[0] = T()' is not a valid 215 expression. */ 216 217 static bool 218 check_op_subscript (...) 219 { 220 return false; 221 } 222 223 /* Check construction with pointer + size. This is a template in 224 order to test both gdb_byte and const gdb_byte. */ 225 226 template<typename T> 227 static void 228 check_ptr_size_ctor () 229 { 230 T data[] = {0x11, 0x22, 0x33, 0x44}; 231 232 gdb::array_view<T> view (data + 1, 2); 233 234 SELF_CHECK (!view.empty ()); 235 SELF_CHECK (view.size () == 2); 236 SELF_CHECK (view.data () == &data[1]); 237 SELF_CHECK (view[0] == data[1]); 238 SELF_CHECK (view[1] == data[2]); 239 240 gdb::array_view<const T> cview (data + 1, 2); 241 SELF_CHECK (!cview.empty ()); 242 SELF_CHECK (cview.size () == 2); 243 SELF_CHECK (cview.data () == &data[1]); 244 SELF_CHECK (cview[0] == data[1]); 245 SELF_CHECK (cview[1] == data[2]); 246 } 247 248 /* Asserts std::is_constructible. */ 249 250 template<typename T, typename... Args> 251 static constexpr bool 252 require_not_constructible () 253 { 254 static_assert (!std::is_constructible<T, Args...>::value, ""); 255 256 /* constexpr functions can't return void in C++11 (N3444). */ 257 return true; 258 }; 259 260 /* Check the array_view<T>(PTR, SIZE) ctor, when T is a pointer. */ 261 262 static void 263 check_ptr_size_ctor2 () 264 { 265 struct A {}; 266 A an_a; 267 268 A *array[] = { &an_a }; 269 const A * const carray[] = { &an_a }; 270 271 gdb::array_view<A *> v1 = {array, ARRAY_SIZE (array)}; 272 gdb::array_view<A *> v2 = {array, (char) ARRAY_SIZE (array)}; 273 gdb::array_view<A * const> v3 = {array, ARRAY_SIZE (array)}; 274 gdb::array_view<const A * const> cv1 = {carray, ARRAY_SIZE (carray)}; 275 276 require_not_constructible<gdb::array_view<A *>, decltype (carray), size_t> (); 277 278 SELF_CHECK (v1[0] == array[0]); 279 SELF_CHECK (v2[0] == array[0]); 280 SELF_CHECK (v3[0] == array[0]); 281 282 SELF_CHECK (!v1.empty ()); 283 SELF_CHECK (v1.size () == 1); 284 SELF_CHECK (v1.data () == &array[0]); 285 286 SELF_CHECK (cv1[0] == carray[0]); 287 288 SELF_CHECK (!cv1.empty ()); 289 SELF_CHECK (cv1.size () == 1); 290 SELF_CHECK (cv1.data () == &carray[0]); 291 } 292 293 /* Check construction with a pair of pointers. This is a template in 294 order to test both gdb_byte and const gdb_byte. */ 295 296 template<typename T> 297 static void 298 check_ptr_ptr_ctor () 299 { 300 T data[] = {0x11, 0x22, 0x33, 0x44}; 301 302 gdb::array_view<T> view (data + 1, data + 3); 303 304 SELF_CHECK (!view.empty ()); 305 SELF_CHECK (view.size () == 2); 306 SELF_CHECK (view.data () == &data[1]); 307 SELF_CHECK (view[0] == data[1]); 308 SELF_CHECK (view[1] == data[2]); 309 310 gdb_byte array[] = {0x11, 0x22, 0x33, 0x44}; 311 const gdb_byte *p1 = array; 312 gdb_byte *p2 = array + ARRAY_SIZE (array); 313 gdb::array_view<const gdb_byte> view2 (p1, p2); 314 } 315 316 /* Check construction with a pair of pointers of mixed constness. */ 317 318 static void 319 check_ptr_ptr_mixed_cv () 320 { 321 gdb_byte array[] = {0x11, 0x22, 0x33, 0x44}; 322 const gdb_byte *cp = array; 323 gdb_byte *p = array; 324 gdb::array_view<const gdb_byte> view1 (cp, p); 325 gdb::array_view<const gdb_byte> view2 (p, cp); 326 SELF_CHECK (view1.empty ()); 327 SELF_CHECK (view2.empty ()); 328 } 329 330 /* Check range-for support (i.e., begin()/end()). This is a template 331 in order to test both gdb_byte and const gdb_byte. */ 332 333 template<typename T> 334 static void 335 check_range_for () 336 { 337 T data[] = {1, 2, 3, 4}; 338 gdb::array_view<T> view (data); 339 340 typename std::decay<T>::type sum = 0; 341 for (auto &elem : view) 342 sum += elem; 343 SELF_CHECK (sum == 1 + 2 + 3 + 4); 344 } 345 346 /* Entry point. */ 347 348 static void 349 run_tests () 350 { 351 /* Empty views. */ 352 { 353 constexpr gdb::array_view<gdb_byte> view1; 354 constexpr gdb::array_view<const gdb_byte> view2; 355 356 static_assert (view1.empty (), ""); 357 static_assert (view1.data () == nullptr, ""); 358 static_assert (view1.size () == 0, ""); 359 static_assert (view2.empty (), ""); 360 static_assert (view2.size () == 0, ""); 361 static_assert (view2.data () == nullptr, ""); 362 } 363 364 std::vector<gdb_byte> vec = {0x11, 0x22, 0x33, 0x44 }; 365 std::array<gdb_byte, 4> array = {{0x11, 0x22, 0x33, 0x44}}; 366 367 /* Various tests of views over std::vector. */ 368 { 369 gdb::array_view<gdb_byte> view = vec; 370 SELF_CHECK (check_container_view (view, vec)); 371 gdb::array_view<const gdb_byte> cview = vec; 372 SELF_CHECK (check_container_view (cview, vec)); 373 } 374 375 /* Likewise, over std::array. */ 376 { 377 gdb::array_view<gdb_byte> view = array; 378 SELF_CHECK (check_container_view (view, array)); 379 gdb::array_view<gdb_byte> cview = array; 380 SELF_CHECK (check_container_view (cview, array)); 381 } 382 383 /* op=(std::vector/std::array/elem) */ 384 { 385 gdb::array_view<gdb_byte> view; 386 387 view = vec; 388 SELF_CHECK (check_container_view (view, vec)); 389 view = std::move (vec); 390 SELF_CHECK (check_container_view (view, vec)); 391 392 view = array; 393 SELF_CHECK (check_container_view (view, array)); 394 view = std::move (array); 395 SELF_CHECK (check_container_view (view, array)); 396 397 gdb_byte elem = 0; 398 view = elem; 399 SELF_CHECK (check_elem_view (view, elem)); 400 view = std::move (elem); 401 SELF_CHECK (check_elem_view (view, elem)); 402 } 403 404 /* Test copy/move ctor and mutable->immutable conversion. */ 405 { 406 gdb_byte data[] = {0x11, 0x22, 0x33, 0x44}; 407 gdb::array_view<gdb_byte> view1 = data; 408 gdb::array_view<gdb_byte> view2 = view1; 409 gdb::array_view<gdb_byte> view3 = std::move (view1); 410 gdb::array_view<const gdb_byte> cview1 = data; 411 gdb::array_view<const gdb_byte> cview2 = cview1; 412 gdb::array_view<const gdb_byte> cview3 = std::move (cview1); 413 SELF_CHECK (view1[0] == data[0]); 414 SELF_CHECK (view2[0] == data[0]); 415 SELF_CHECK (view3[0] == data[0]); 416 SELF_CHECK (cview1[0] == data[0]); 417 SELF_CHECK (cview2[0] == data[0]); 418 SELF_CHECK (cview3[0] == data[0]); 419 } 420 421 /* Same, but op=(view). */ 422 { 423 gdb_byte data[] = {0x55, 0x66, 0x77, 0x88}; 424 gdb::array_view<gdb_byte> view1; 425 gdb::array_view<gdb_byte> view2; 426 gdb::array_view<gdb_byte> view3; 427 gdb::array_view<const gdb_byte> cview1; 428 gdb::array_view<const gdb_byte> cview2; 429 gdb::array_view<const gdb_byte> cview3; 430 431 view1 = data; 432 view2 = view1; 433 view3 = std::move (view1); 434 cview1 = data; 435 cview2 = cview1; 436 cview3 = std::move (cview1); 437 SELF_CHECK (view1[0] == data[0]); 438 SELF_CHECK (view2[0] == data[0]); 439 SELF_CHECK (view3[0] == data[0]); 440 SELF_CHECK (cview1[0] == data[0]); 441 SELF_CHECK (cview2[0] == data[0]); 442 SELF_CHECK (cview3[0] == data[0]); 443 } 444 445 /* op[] */ 446 { 447 std::vector<gdb_byte> vec2 = {0x11, 0x22}; 448 gdb::array_view<gdb_byte> view = vec2; 449 gdb::array_view<const gdb_byte> cview = vec2; 450 451 /* Check that op[] on a non-const view of non-const T returns a 452 mutable reference. */ 453 view[0] = 0x33; 454 SELF_CHECK (vec2[0] == 0x33); 455 456 /* OTOH, check that assigning through op[] on a view of const T 457 wouldn't compile. */ 458 SELF_CHECK (!check_op_subscript (cview)); 459 /* For completeness. */ 460 SELF_CHECK (check_op_subscript (view)); 461 } 462 463 check_ptr_size_ctor<const gdb_byte> (); 464 check_ptr_size_ctor<gdb_byte> (); 465 check_ptr_size_ctor2 (); 466 check_ptr_ptr_ctor<const gdb_byte> (); 467 check_ptr_ptr_ctor<gdb_byte> (); 468 check_ptr_ptr_mixed_cv (); 469 470 check_range_for<gdb_byte> (); 471 check_range_for<const gdb_byte> (); 472 473 /* Check that the right ctor overloads are taken when the element is 474 a container. */ 475 { 476 using Vec = std::vector<gdb_byte>; 477 Vec vecs[3]; 478 479 gdb::array_view<Vec> view_array = vecs; 480 SELF_CHECK (view_array.size () == 3); 481 482 Vec elem; 483 gdb::array_view<Vec> view_elem = elem; 484 SELF_CHECK (view_elem.size () == 1); 485 } 486 487 /* gdb::make_array_view, int length. */ 488 { 489 gdb_byte data[] = {0x55, 0x66, 0x77, 0x88}; 490 int len = sizeof (data) / sizeof (data[0]); 491 auto view = gdb::make_array_view (data, len); 492 493 SELF_CHECK (view.data () == data); 494 SELF_CHECK (view.size () == len); 495 496 for (size_t i = 0; i < len; i++) 497 SELF_CHECK (view[i] == data[i]); 498 } 499 500 /* Test slicing. */ 501 { 502 gdb_byte data[] = {0x55, 0x66, 0x77, 0x88, 0x99}; 503 gdb::array_view<gdb_byte> view = data; 504 505 { 506 auto slc = view.slice (1, 3); 507 SELF_CHECK (slc.data () == data + 1); 508 SELF_CHECK (slc.size () == 3); 509 SELF_CHECK (slc[0] == data[1]); 510 SELF_CHECK (slc[0] == view[1]); 511 } 512 513 { 514 auto slc = view.slice (2); 515 SELF_CHECK (slc.data () == data + 2); 516 SELF_CHECK (slc.size () == 3); 517 SELF_CHECK (slc[0] == view[2]); 518 SELF_CHECK (slc[0] == data[2]); 519 } 520 } 521 } 522 523 } /* namespace array_view_tests */ 524 } /* namespace selftests */ 525 526 void _initialize_array_view_selftests (); 527 void 528 _initialize_array_view_selftests () 529 { 530 selftests::register_test ("array_view", 531 selftests::array_view_tests::run_tests); 532 } 533