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