1 #ifndef Corrade_Containers_Array_h 2 #define Corrade_Containers_Array_h 3 /* 4 This file is part of Corrade. 5 6 Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 7 2017, 2018, 2019, 2020 Vladimír Vondruš <mosra@centrum.cz> 8 9 Permission is hereby granted, free of charge, to any person obtaining a 10 copy of this software and associated documentation files (the "Software"), 11 to deal in the Software without restriction, including without limitation 12 the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 and/or sell copies of the Software, and to permit persons to whom the 14 Software is furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included 17 in all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 */ 27 28 /** @file 29 * @brief Class @ref Corrade::Containers::Array 30 */ 31 32 #include <initializer_list> 33 #include <new> 34 #include <type_traits> 35 #include <utility> 36 37 #include "Corrade/configure.h" 38 #include "Corrade/Containers/ArrayView.h" 39 #include "Corrade/Containers/Tags.h" 40 #include "Corrade/Containers/constructHelpers.h" 41 42 namespace Corrade { namespace Containers { 43 44 namespace Implementation { 45 template<class T> struct DefaultDeleter { operatorDefaultDeleter46 T operator()() const { return T{}; } 47 }; 48 template<class T> struct DefaultDeleter<void(*)(T*, std::size_t)> { 49 void(*operator()() const)(T*, std::size_t) { return nullptr; } 50 }; 51 52 template<class T, class D> struct CallDeleter { 53 void operator()(D deleter, T* data, std::size_t size) const { 54 deleter(data, size); 55 } 56 }; 57 template<class T> struct CallDeleter<T, void(*)(T*, std::size_t)> { 58 void operator()(void(*deleter)(T*, std::size_t), T* data, std::size_t size) const { 59 if(deleter) deleter(data, size); 60 else delete[] data; 61 } 62 }; 63 64 template<class T> T* noInitAllocate(std::size_t size, typename std::enable_if<std::is_trivial<T>::value>::type* = nullptr) { 65 return new T[size]; 66 } 67 template<class T> T* noInitAllocate(std::size_t size, typename std::enable_if<!std::is_trivial<T>::value>::type* = nullptr) { 68 return reinterpret_cast<T*>(new char[size*sizeof(T)]); 69 } 70 71 template<class T> auto noInitDeleter(typename std::enable_if<std::is_trivial<T>::value>::type* = nullptr) -> void(*)(T*, std::size_t) { 72 return nullptr; /* using the default deleter for T */ 73 } 74 template<class T> auto noInitDeleter(typename std::enable_if<!std::is_trivial<T>::value>::type* = nullptr) -> void(*)(T*, std::size_t) { 75 return [](T* data, std::size_t size) { 76 if(data) for(T *it = data, *end = data + size; it != end; ++it) 77 it->~T(); 78 delete[] reinterpret_cast<char*>(data); 79 }; 80 } 81 } 82 83 /** 84 @brief Array wrapper with size information 85 @tparam T Element type 86 @tparam D Deleter type. Defaults to pointer to a @cpp void(T*, std::size_t) @ce 87 function, where first is array pointer and second array size 88 89 Provides a RAII wrapper around a plain C array. A lighter alternative to 90 @ref std::vector that's deliberately move-only to avoid accidental copies of 91 large memory blocks. It's usable in STL algorithms in the same way as a plain C 92 array as well as in range-for cycles and other APIs operating with iterators. 93 By default the array has a non-changeable size by default and growing 94 functionality is opt-in, see @ref Containers-Array-growable below for more 95 information. Usage example: 96 97 @snippet Containers.cpp Array-usage 98 99 @section Containers-Array-initialization Array initialization 100 101 The array is by default *value-initialized*, which means that trivial types 102 are zero-initialized and the default constructor is called on other types. It 103 is possible to initialize the array in a different way using so-called *tags*: 104 105 - @ref Array(DefaultInitT, std::size_t) leaves trivial types uninitialized 106 and calls the default constructor elsewhere. In other words, 107 @cpp new T[size] @ce. 108 - @ref Array(ValueInitT, std::size_t) is equivalent to the default case, 109 zero-initializing trivial types and calling the default constructor 110 elsewhere. Useful when you want to make the choice appear explicit. In 111 other words, @cpp new T[size]{} @ce. 112 - @ref Array(DirectInitT, std::size_t, Args&&... args) constructs all 113 elements of the array using provided arguments. In other words, 114 @cpp new T[size]{T{args...}, T{args...}, …} @ce. 115 - @ref Array(InPlaceInitT, std::initializer_list<T>) allocates unitialized 116 memory and then copy-constructs all elements from the initializer list. In 117 other words, @cpp new T[size]{args...} @ce. 118 - @ref Array(NoInitT, std::size_t) does not initialize anything and you need 119 to call the constructor on all elements manually using placement new, 120 @ref std::uninitialized_copy() or similar. This is the dangerous option. 121 In other words, @cpp new char[size*sizeof(T)] @ce for non-trivial types 122 to circumvent default construction and @cpp new T[size] @ce for trivial 123 types. 124 125 Example: 126 127 @snippet Containers.cpp Array-initialization 128 129 @section Containers-Array-wrapping Wrapping externally allocated arrays 130 131 By default the class makes all allocations using @cpp operator new[] @ce and 132 deallocates using @cpp operator delete[] @ce for given @p T, with some 133 additional trickery done internally to make the @ref Array(NoInitT, std::size_t) 134 and @ref Array(DirectInitT, std::size_t, Args&&... args) constructors work. 135 When wrapping an externally allocated array using @ref Array(T*, std::size_t, D), 136 it is possible to specify which function to use for deallocation. By default 137 the deleter is set to @cpp nullptr @ce, which is equivalent to deleting the 138 contents using @cpp operator delete[] @ce. 139 140 For example, properly deallocating array allocated using @ref std::malloc(): 141 142 @snippet Containers.cpp Array-wrapping 143 144 By default, plain function pointers are used to avoid having the type affected 145 by the deleter function. If the deleter needs to manage some state, a custom 146 deleter type can be used: 147 148 @snippet Containers.cpp Array-deleter 149 150 @section Containers-Array-growable Growable arrays 151 152 The @ref Array class provides no reallocation or growing capabilities on its 153 own, and this functionality is opt-in via free functions from 154 @ref Corrade/Containers/GrowableArray.h instead. This is done in order to keep 155 the concept of an owning container decoupled from the extra baggage coming from 156 custom allocators, type constructibility and such. 157 158 As long as the type stored in the array is nothrow-move-constructible, any 159 @ref Array instance can be converted to a growing container by calling the 160 family of @ref arrayAppend(), @ref arrayReserve(), @ref arrayResize() ... 161 functions. A growable array behaves the same as a regular array to its 162 consumers --- its @ref size() returns the count of *real* elements, while 163 available capacity can be queried through @ref arrayCapacity(). Example of 164 populating an array with an undetermined amount of elements: 165 166 @snippet Containers.cpp Array-growable 167 168 A growable array can be turned back into a regular one using 169 @ref arrayShrink() if desired. That'll free all extra memory, moving the 170 elements to an array of exactly the size needed. 171 172 @m_class{m-block m-success} 173 174 @par Tip 175 To save typing, you can make use of ADL and call the @ref arrayAppend() 176 etc. functions unqualified, without having them explicitly prefixed with 177 @cpp Containers:: @ce. 178 179 @subsection Containers-Array-growable-allocators Growable allocators 180 181 Similarly to standard containers, growable arrays allow you to use a custom 182 allocator that matches the documented semantics of @ref ArrayAllocator. It's 183 also possible to switch between different allocators during the lifetime of an 184 @ref Array instance --- internally it's the same process as when a non-growable 185 array is converted to a growable version (or back, with @ref arrayShrink()). 186 187 The @ref ArrayAllocator is by default aliased to @ref ArrayNewAllocator, which 188 uses the standard C++ @cpp new[] @ce / @cpp delete[] @ce constructs and is 189 fully move-aware, requiring the types to be only nothrow-move-constructible at 190 the very least. If a type is trivially copyable, the @ref ArrayMallocAllocator 191 will get picked instead, make use of @ref std::realloc() to avoid unnecessary 192 memory copies when growing the array. The typeless nature of 193 @ref ArrayMallocAllocator internals allows for free type-casting of the array 194 instance with @ref arrayAllocatorCast(), an operation not easily doable using 195 typed allocators. 196 197 @subsection Containers-Array-growable-sanitizer AddressSanitizer container annotations 198 199 Because the alloacted growable arrays have an area between @ref size() and 200 @ref arrayCapacity() that shouldn't be accessed, when building with 201 [Address Sanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) 202 enabled, this area is marked as "container overflow". Given the following code, 203 ASan aborts and produces a failure report similar to the one below: 204 205 @m_class{m-code-figure} 206 207 @parblock 208 209 @snippet Containers.cpp Array-growable-sanitizer 210 211 <p></p> 212 213 @m_class{m-nopad} 214 215 @include containers-growable-array-sanitizer.ansi 216 217 @endparblock 218 219 @section Containers-Array-views Conversion to array views 220 221 Arrays are implicitly convertible to @ref ArrayView as described in the 222 following table. The conversion is only allowed if @cpp T* @ce is implicitly 223 convertible to @cpp U* @ce (or both are the same type) and both have the same 224 size. This also extends to other container types constructibe from 225 @ref ArrayView, which means for example that a @ref StridedArrayView1D is 226 implicitly convertible from @ref Array as well. 227 228 Owning array type | ↭ | Non-owning view type 229 ------------------------------- | - | --------------------- 230 @ref Array "Array<T>" | → | @ref ArrayView "ArrayView<U>" 231 @ref Array "Array<T>" | → | @ref ArrayView "ArrayView<const U>" 232 @ref Array "const Array<T>" | → | @ref ArrayView "ArrayView<const U>" 233 234 @section Containers-Array-stl STL compatibility 235 236 On compilers that support C++2a and @ref std::span, implicit conversion of an 237 @ref Array to it is provided in @ref Corrade/Containers/ArrayViewStlSpan.h. The 238 conversion is provided in a separate header to avoid unconditional 239 @cpp #include <span> @ce, which significantly affects compile times. The 240 following table lists allowed conversions: 241 242 Corrade type | ↭ | STL type 243 ------------------------------- | - | --------------------- 244 @ref Array "Array<T>" | → | @ref std::span "std::span<T>" 245 @ref Array "Array<T>" | → | @ref std::span "std::span<const T>" 246 @ref Array "const Array<T>" | → | @ref std::span "std::span<const T>" 247 248 There are some dangerous corner cases due to the way @ref std::span is 249 designed, see @ref Containers-ArrayView-stl "ArrayView STL compatibility" for 250 more information. 251 252 @m_class{m-block m-success} 253 254 @par Single-header version 255 This class, together with @ref StaticArray, is also available as a 256 single-header [CorradeArray.h](https://github.com/mosra/magnum-singles/tree/master/CorradeArray.h) 257 library in the Magnum Singles repository for easier integration into your 258 projects. See @ref corrade-singles for more information. 259 260 @see @ref arrayCast(Array<T, D>&), @ref StaticArray 261 */ 262 #ifdef DOXYGEN_GENERATING_OUTPUT 263 template<class T, class D = void(*)(T*, std::size_t)> 264 #else 265 template<class T, class D> 266 #endif 267 class Array { 268 /* Ideally this could be derived from ArrayView<T>, avoiding a lot of 269 redundant code, however I'm unable to find a way to add const/non-const 270 overloads of all slicing functions and also prevent const Array<T>& from 271 being sliced to a (mutable) ArrayView<T>. */ 272 273 public: 274 typedef T Type; /**< @brief Element type */ 275 typedef D Deleter; /**< @brief Deleter type */ 276 277 /** @brief Conversion from nullptr */ 278 #ifdef DOXYGEN_GENERATING_OUTPUT 279 /*implicit*/ Array(std::nullptr_t) noexcept: 280 #else 281 template<class U, class V = typename std::enable_if<std::is_same<std::nullptr_t, U>::value>::type> /*implicit*/ Array(U) noexcept: 282 #endif 283 /* GCC <=4.8 breaks on _deleter{} */ 284 _data{nullptr}, _size{0}, _deleter(Implementation::DefaultDeleter<D>{}()) {} 285 286 /** 287 * @brief Default constructor 288 * 289 * Creates a zero-sized array. Move an array with a nonzero size onto 290 * the instance to make it useful. 291 */ 292 /* GCC <=4.8 breaks on _deleter{} */ 293 /*implicit*/ Array() noexcept: _data(nullptr), _size(0), _deleter(Implementation::DefaultDeleter<D>{}()) {} 294 295 /** 296 * @brief Construct a default-initialized array 297 * 298 * Creates array of given size, the contents are default-initialized 299 * (i.e. builtin types are not initialized). If the size is zero, no 300 * allocation is done. 301 * @see @ref DefaultInit, @ref Array(ValueInitT, std::size_t) 302 */ 303 explicit Array(DefaultInitT, std::size_t size): _data{size ? new T[size] : nullptr}, _size{size}, _deleter{nullptr} {} 304 305 /** 306 * @brief Construct a value-initialized array 307 * 308 * Creates array of given size, the contents are value-initialized 309 * (i.e. builtin types are zero-initialized). For other than builtin 310 * types this is the same as @ref Array(std::size_t). If the size is 311 * zero, no allocation is done. 312 * 313 * Useful if you want to create an array of primitive types and set 314 * them to zero. 315 * @see @ref ValueInit, @ref Array(DefaultInitT, std::size_t) 316 */ 317 explicit Array(ValueInitT, std::size_t size): _data{size ? new T[size]() : nullptr}, _size{size}, _deleter{nullptr} {} 318 319 /** 320 * @brief Construct an array without initializing its contents 321 * 322 * Creates array of given size, the contents are *not* initialized. If 323 * the size is zero, no allocation is done. Initialize the values using 324 * placement new. Useful if you will be overwriting all elements later 325 * anyway. 326 * 327 * - For non-trivial types, the data are allocated as a 328 * @cpp char @ce array. Destruction is done using a custom deleter 329 * that explicitly calls destructor on *all elements* (regardless 330 * of whether they were properly constructed or not) and then 331 * deallocates the data as a @cpp char @ce array again. 332 * - For trivial types is equivalent to 333 * @ref Array(DefaultInitT, std::size_t), with @ref deleter() 334 * being the default (@cpp nullptr @ce) as well. This is done in 335 * order to avoid needless problems with dangling custom deleters 336 * when returning arrays from dynamically loaded libraries. 337 * 338 * @see @ref NoInit, @ref Array(DirectInitT, std::size_t, Args&&... args), 339 * @ref deleter(), @ref std::is_trivial 340 */ 341 explicit Array(NoInitT, std::size_t size): _data{size ? Implementation::noInitAllocate<T>(size) : nullptr}, _size{size}, _deleter{Implementation::noInitDeleter<T>()} {} 342 343 /** 344 * @brief Construct a direct-initialized array 345 * 346 * Allocates the array using the @ref Array(NoInitT, std::size_t) 347 * constructor and then initializes each element with placement new 348 * using forwarded @p args. 349 */ 350 template<class... Args> explicit Array(DirectInitT, std::size_t size, Args&&... args); 351 352 /** 353 * @brief Construct a list-initialized array 354 * 355 * Allocates the array using the @ref Array(NoInitT, std::size_t) 356 * constructor and then copy-initializes each element with placement 357 * new using values from @p list. 358 * 359 * Note that there's no plain initializer-list constructor because it 360 * would cause a similar fiasco as with @ref std::vector, where 361 * @cpp std::vector<int>{5} @ce creates one-element vector but 362 * @cpp std::vector<int>(5) @ce creates a zero-initialized five-element 363 * vector. To save typing, you can use the 364 * @ref array(std::initializer_list<T>) helper which doesn't suffer 365 * from this problem. 366 */ 367 explicit Array(InPlaceInitT, std::initializer_list<T> list); 368 369 /** 370 * @brief Construct a value-initialized array 371 * 372 * Alias to @ref Array(ValueInitT, std::size_t). 373 * @see @ref Array(DefaultInitT, std::size_t) 374 */ 375 explicit Array(std::size_t size): Array{ValueInit, size} {} 376 377 /** 378 * @brief Wrap an existing array 379 * 380 * Note that the array will be deleted on destruction using given 381 * @p deleter. See class documentation for more information about 382 * custom deleters and @ref ArrayView for non-owning array wrapper. 383 */ 384 /* GCC <=4.8 breaks on _deleter{} */ 385 explicit Array(T* data, std::size_t size, D deleter = Implementation::DefaultDeleter<D>{}()): _data{data}, _size{size}, _deleter(deleter) {} 386 387 /** 388 * @brief Destructor 389 * 390 * Calls @ref deleter() on the owned @ref data(). 391 */ 392 ~Array() { Implementation::CallDeleter<T, D>{}(_deleter, _data, _size); } 393 394 /** @brief Copying is not allowed */ 395 Array(const Array<T, D>&) = delete; 396 397 /** 398 * @brief Move constructor 399 * 400 * Resets data pointer, size and deleter of @p other to be equivalent 401 * to a default-constructed instance. 402 */ 403 Array(Array<T, D>&& other) noexcept; 404 405 /** @brief Copying is not allowed */ 406 Array<T, D>& operator=(const Array<T, D>&) = delete; 407 408 /** 409 * @brief Move assignment 410 * 411 * Swaps data pointer, size and deleter of the two instances. 412 */ 413 Array<T, D>& operator=(Array<T, D>&& other) noexcept; 414 415 /* The following view conversion is *not* restricted to this& because 416 that would break uses like `consume(foo());`, where `consume()` 417 expects a view but `foo()` returns an owning array. */ 418 419 /** 420 * @brief Convert to external view representation 421 * 422 * @see @ref Containers-Array-stl 423 */ 424 template<class U, class = decltype(Implementation::ArrayViewConverter<T, U>::to(std::declval<ArrayView<T>>()))> /*implicit*/ operator U() { 425 return Implementation::ArrayViewConverter<T, U>::to(*this); 426 } 427 428 /** @overload */ 429 template<class U, class = decltype(Implementation::ArrayViewConverter<const T, U>::to(std::declval<ArrayView<const T>>()))> constexpr /*implicit*/ operator U() const { 430 return Implementation::ArrayViewConverter<const T, U>::to(*this); 431 } 432 433 #ifndef CORRADE_MSVC2019_COMPATIBILITY 434 /** @brief Whether the array is non-empty */ 435 /* Disabled on MSVC <= 2017 to avoid ambiguous operator+() when doing 436 pointer arithmetic. On MSVC 2019 this works properly when 437 /permissive- is enabled, but I can neither detect a presence of that 438 flag nor force it for all users (since it often ICEs and breaks 3rd 439 party code), so disabling for 2019 as well. */ 440 explicit operator bool() const { return _data; } 441 #endif 442 443 /* `char* a = Containers::Array<char>(5); a[3] = 5;` would result in 444 instant segfault, disallowing it in the following conversion 445 operators */ 446 447 /** @brief Conversion to array type */ 448 /*implicit*/ operator T*() & { return _data; } 449 450 /** @overload */ 451 /*implicit*/ operator const T*() const & { return _data; } 452 453 /** @brief Array data */ 454 T* data() { return _data; } 455 const T* data() const { return _data; } /**< @overload */ 456 457 /** 458 * @brief Array deleter 459 * 460 * If set to @cpp nullptr @ce, the contents are deleted using standard 461 * @cpp operator delete[] @ce. 462 * @see @ref Array(T*, std::size_t, D) 463 */ 464 D deleter() const { return _deleter; } 465 466 /** @brief Array size */ 467 std::size_t size() const { return _size; } 468 469 /** @brief Whether the array is empty */ 470 bool empty() const { return !_size; } 471 472 /** 473 * @brief Pointer to first element 474 * 475 * @see @ref front() 476 */ 477 T* begin() { return _data; } 478 const T* begin() const { return _data; } /**< @overload */ 479 const T* cbegin() const { return _data; } /**< @overload */ 480 481 /** 482 * @brief Pointer to (one item after) last element 483 * 484 * @see @ref back() 485 */ 486 T* end() { return _data+_size; } 487 const T* end() const { return _data+_size; } /**< @overload */ 488 const T* cend() const { return _data+_size; } /**< @overload */ 489 490 /** 491 * @brief First element 492 * 493 * Expects there is at least one element. 494 * @see @ref begin() 495 */ 496 T& front(); 497 const T& front() const; /**< @overload */ 498 499 /** 500 * @brief Last element 501 * 502 * Expects there is at least one element. 503 * @see @ref end() 504 */ 505 T& back(); 506 const T& back() const; /**< @overload */ 507 508 /** 509 * @brief Reference to array slice 510 * 511 * Equivalent to @ref ArrayView::slice(). 512 */ 513 ArrayView<T> slice(T* begin, T* end) { 514 return ArrayView<T>(*this).slice(begin, end); 515 } 516 /** @overload */ 517 ArrayView<const T> slice(const T* begin, const T* end) const { 518 return ArrayView<const T>(*this).slice(begin, end); 519 } 520 /** @overload */ 521 ArrayView<T> slice(std::size_t begin, std::size_t end) { 522 return ArrayView<T>(*this).slice(begin, end); 523 } 524 /** @overload */ 525 ArrayView<const T> slice(std::size_t begin, std::size_t end) const { 526 return ArrayView<const T>(*this).slice(begin, end); 527 } 528 529 /** 530 * @brief Fixed-size array slice 531 * 532 * Both @cpp begin @ce and @cpp begin + size @ce are expected to be in 533 * range. 534 */ 535 template<std::size_t size> StaticArrayView<size, T> slice(T* begin) { 536 return ArrayView<T>(*this).template slice<size>(begin); 537 } 538 /** @overload */ 539 template<std::size_t size> StaticArrayView<size, const T> slice(const T* begin) const { 540 return ArrayView<const T>(*this).template slice<size>(begin); 541 } 542 /** @overload */ 543 template<std::size_t size> StaticArrayView<size, T> slice(std::size_t begin) { 544 return ArrayView<T>(*this).template slice<size>(begin); 545 } 546 /** @overload */ 547 template<std::size_t size> StaticArrayView<size, const T> slice(std::size_t begin) const { 548 return ArrayView<const T>(*this).template slice<size>(begin); 549 } 550 551 /** 552 * @brief Fixed-size array slice 553 * @m_since{2019,10} 554 * 555 * At compile time expects that @cpp begin < end_ @ce, at runtime that 556 * @p end_ is not larger than @ref size(). 557 */ 558 template<std::size_t begin_, std::size_t end_> StaticArrayView<end_ - begin_, T> slice() { 559 return ArrayView<T>(*this).template slice<begin_, end_>(); 560 } 561 562 /** 563 * @overload 564 * @m_since{2019,10} 565 */ 566 template<std::size_t begin_, std::size_t end_> StaticArrayView<end_ - begin_, const T> slice() const { 567 return ArrayView<const T>(*this).template slice<begin_, end_>(); 568 } 569 570 /** 571 * @brief Array prefix 572 * 573 * Equivalent to @ref ArrayView::prefix(). 574 */ 575 ArrayView<T> prefix(T* end) { 576 return ArrayView<T>(*this).prefix(end); 577 } 578 /** @overload */ 579 ArrayView<const T> prefix(const T* end) const { 580 return ArrayView<const T>(*this).prefix(end); 581 } 582 /** @overload */ 583 ArrayView<T> prefix(std::size_t end) { 584 return ArrayView<T>(*this).prefix(end); 585 } 586 /** @overload */ 587 ArrayView<const T> prefix(std::size_t end) const { 588 return ArrayView<const T>(*this).prefix(end); 589 } 590 591 /** @overload */ 592 template<std::size_t viewSize> StaticArrayView<viewSize, T> prefix() { 593 return ArrayView<T>(*this).template prefix<viewSize>(); 594 } 595 /** @overload */ 596 template<std::size_t viewSize> StaticArrayView<viewSize, const T> prefix() const { 597 return ArrayView<const T>(*this).template prefix<viewSize>(); 598 } 599 600 /** 601 * @brief Array suffix 602 * 603 * Equivalent to @ref ArrayView::suffix(). 604 */ 605 ArrayView<T> suffix(T* begin) { 606 return ArrayView<T>(*this).suffix(begin); 607 } 608 /** @overload */ 609 ArrayView<const T> suffix(const T* begin) const { 610 return ArrayView<const T>(*this).suffix(begin); 611 } 612 /** @overload */ 613 ArrayView<T> suffix(std::size_t begin) { 614 return ArrayView<T>(*this).suffix(begin); 615 } 616 /** @overload */ 617 ArrayView<const T> suffix(std::size_t begin) const { 618 return ArrayView<const T>(*this).suffix(begin); 619 } 620 621 /** 622 * @brief Array prefix except the last @p count items 623 * @m_since{2019,10} 624 * 625 * Equivalent to @ref ArrayView::except(). 626 */ 627 ArrayView<T> except(std::size_t count) { 628 return ArrayView<T>(*this).except(count); 629 } 630 /** 631 * @overload 632 * @m_since{2019,10} 633 */ 634 ArrayView<const T> except(std::size_t count) const { 635 return ArrayView<const T>(*this).except(count); 636 } 637 638 /** 639 * @brief Release data storage 640 * 641 * Returns the data pointer and resets data pointer, size and deleter 642 * to be equivalent to a default-constructed instance. Deleting the 643 * returned array is user responsibility --- note the array might have 644 * a custom @ref deleter() and so @cpp delete[] @ce might not be always 645 * appropriate. 646 */ 647 T* release(); 648 649 private: 650 T* _data; 651 std::size_t _size; 652 D _deleter; 653 }; 654 655 /** @relatesalso Array 656 @brief Construct a list-initialized array 657 @m_since{2020,06} 658 659 Convenience shortcut to the @ref Array::Array(InPlaceInitT, std::initializer_list<T>) 660 constructor. See its documentation for a design rationale. 661 */ 662 template<class T> inline Array<T> array(std::initializer_list<T> list) { 663 return Array<T>{InPlaceInit, list}; 664 } 665 666 /** @relatesalso ArrayView 667 @brief Make view on @ref Array 668 669 Convenience alternative to converting to an @ref ArrayView explicitly. The 670 following two lines are equivalent: 671 672 @snippet Containers.cpp Array-arrayView 673 */ 674 template<class T, class D> inline ArrayView<T> arrayView(Array<T, D>& array) { 675 return ArrayView<T>{array}; 676 } 677 678 /** @relatesalso ArrayView 679 @brief Make view on const @ref Array 680 681 Convenience alternative to converting to an @ref ArrayView explicitly. The 682 following two lines are equivalent: 683 684 @snippet Containers.cpp Array-arrayView-const 685 */ 686 template<class T, class D> inline ArrayView<const T> arrayView(const Array<T, D>& array) { 687 return ArrayView<const T>{array}; 688 } 689 690 /** @relatesalso Array 691 @brief Reinterpret-cast an array 692 693 See @ref arrayCast(ArrayView<T>) for more information. 694 */ 695 template<class U, class T, class D> inline ArrayView<U> arrayCast(Array<T, D>& array) { 696 return arrayCast<U>(arrayView(array)); 697 } 698 699 /** @overload */ 700 template<class U, class T, class D> inline ArrayView<const U> arrayCast(const Array<T, D>& array) { 701 return arrayCast<const U>(arrayView(array)); 702 } 703 704 /** @relatesalso Array 705 @brief Array size 706 707 See @ref arraySize(ArrayView<T>) for more information. 708 */ 709 template<class T> std::size_t arraySize(const Array<T>& view) { 710 return view.size(); 711 } 712 713 template<class T, class D> inline Array<T, D>::Array(Array<T, D>&& other) noexcept: _data{other._data}, _size{other._size}, _deleter{other._deleter} { 714 other._data = nullptr; 715 other._size = 0; 716 other._deleter = D{}; 717 } 718 719 template<class T, class D> template<class ...Args> Array<T, D>::Array(DirectInitT, std::size_t size, Args&&... args): Array{NoInit, size} { 720 for(std::size_t i = 0; i != size; ++i) 721 Implementation::construct(_data[i], std::forward<Args>(args)...); 722 } 723 724 template<class T, class D> Array<T, D>::Array(InPlaceInitT, std::initializer_list<T> list): Array{NoInit, list.size()} { 725 std::size_t i = 0; 726 for(const T& item: list) new(_data + i++) T{item}; 727 } 728 729 template<class T, class D> inline Array<T, D>& Array<T, D>::operator=(Array<T, D>&& other) noexcept { 730 using std::swap; 731 swap(_data, other._data); 732 swap(_size, other._size); 733 swap(_deleter, other._deleter); 734 return *this; 735 } 736 737 template<class T, class D> const T& Array<T, D>::front() const { 738 CORRADE_ASSERT(_size, "Containers::Array::front(): array is empty", _data[0]); 739 return _data[0]; 740 } 741 742 template<class T, class D> const T& Array<T, D>::back() const { 743 CORRADE_ASSERT(_size, "Containers::Array::back(): array is empty", _data[_size - 1]); 744 return _data[_size - 1]; 745 } 746 747 template<class T, class D> T& Array<T, D>::front() { 748 return const_cast<T&>(static_cast<const Array<T, D>&>(*this).front()); 749 } 750 751 template<class T, class D> T& Array<T, D>::back() { 752 return const_cast<T&>(static_cast<const Array<T, D>&>(*this).back()); 753 } 754 755 template<class T, class D> inline T* Array<T, D>::release() { 756 T* const data = _data; 757 _data = nullptr; 758 _size = 0; 759 _deleter = D{}; 760 return data; 761 } 762 763 namespace Implementation { 764 765 /* Array to ArrayView in order to have implicit conversion for StridedArrayView 766 without needing to introduce a header dependency. The SFINAE needs to be 767 here in order to ensure proper behavior with function overloads taking more 768 than one type of (Strided)ArrayView. */ 769 template<class U, class T, class D> struct ArrayViewConverter<U, Array<T, D>> { 770 template<class V = U> constexpr static typename std::enable_if<std::is_convertible<T*, V*>::value, ArrayView<U>>::type from(Array<T, D>& other) { 771 static_assert(sizeof(T) == sizeof(U), "types are not compatible"); 772 return {&other[0], other.size()}; 773 } 774 template<class V = U> constexpr static typename std::enable_if<std::is_convertible<T*, V*>::value, ArrayView<U>>::type from(Array<T, D>&& other) { 775 static_assert(sizeof(T) == sizeof(U), "types are not compatible"); 776 return {&other[0], other.size()}; 777 } 778 }; 779 template<class U, class T, class D> struct ArrayViewConverter<const U, Array<T, D>> { 780 template<class V = U> constexpr static typename std::enable_if<std::is_convertible<T*, V*>::value, ArrayView<const U>>::type from(const Array<T, D>& other) { 781 static_assert(sizeof(T) == sizeof(U), "types are not compatible"); 782 return {&other[0], other.size()}; 783 } 784 }; 785 template<class U, class T, class D> struct ArrayViewConverter<const U, Array<const T, D>> { 786 template<class V = U> constexpr static typename std::enable_if<std::is_convertible<T*, V*>::value, ArrayView<const U>>::type from(const Array<const T, D>& other) { 787 static_assert(sizeof(T) == sizeof(U), "types are not compatible"); 788 return {&other[0], other.size()}; 789 } 790 }; 791 template<class T, class D> struct ErasedArrayViewConverter<Array<T, D>>: ArrayViewConverter<T, Array<T, D>> {}; 792 template<class T, class D> struct ErasedArrayViewConverter<const Array<T, D>>: ArrayViewConverter<const T, Array<T, D>> {}; 793 794 } 795 796 }} 797 798 #endif 799