1/*
2 * Copyright (C) 2018 Yusuke Suzuki <utatane.tea@gmail.com>. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include <wtf/CheckedArithmetic.h>
29#include <wtf/FastMalloc.h>
30#include <wtf/Vector.h>
31
32namespace WTF {
33
34template<bool isTriviallyDestructible, typename T> struct UniqueArrayMaker;
35
36template<typename T>
37struct UniqueArrayMaker<true, T> {
38 using ResultType = typename std::unique_ptr<T[], FastFree<T[]>>;
39
40 static ResultType make(size_t size)
41 {
42 // C++ `new T[N]` stores its `N` to somewhere. Otherwise, `delete []` cannot destroy
43 // these N elements. But we do not want to increase the size of allocated memory.
44 // If it is acceptable, we can just use Vector<T> instead. So this UniqueArray<T> only
45 // accepts the type T which has a trivial destructor. This allows us to skip calling
46 // destructors for N elements. And this allows UniqueArray<T> not to store its N size.
47 static_assert(std::is_trivially_destructible<T>::value, "");
48
49 // Do not use placement new like `new (storage) T[size]()`. `new T[size]()` requires
50 // larger storage than the `sizeof(T) * size` storage since it want to store `size`
51 // to somewhere.
52 T* storage = static_cast<T*>(fastMalloc((Checked<size_t>(sizeof(T)) * size).unsafeGet()));
53 VectorTypeOperations<T>::initialize(storage, storage + size);
54 return ResultType(storage);
55 }
56};
57
58template<typename T>
59struct UniqueArrayMaker<false, T> {
60 // Since we do not know how to store/retrieve N size to/from allocated memory when calling new [] and delete [],
61 // we use new [] and delete [] operators simply. We create UniqueArrayElement container for the type T.
62 // UniqueArrayElement has new [] and delete [] operators for FastMalloc. We allocate UniqueArrayElement[] and cast
63 // it to T[]. When deleting, the custom deleter casts T[] to UniqueArrayElement[] and deletes it.
64 class UniqueArrayElement {
65 WTF_MAKE_FAST_ALLOCATED;
66 public:
67 struct Deleter {
68 void operator()(T* pointer)
69 {
70 delete [] bitwise_cast<UniqueArrayElement*>(pointer);
71 };
72 };
73
74 UniqueArrayElement() = default;
75
76 T value { };
77 };
78 static_assert(sizeof(T) == sizeof(UniqueArrayElement), "");
79
80 using ResultType = typename std::unique_ptr<T[], typename UniqueArrayElement::Deleter>;
81
82 static ResultType make(size_t size)
83 {
84 return ResultType(bitwise_cast<T*>(new UniqueArrayElement[size]()));
85 }
86};
87
88template<typename T>
89using UniqueArray = typename UniqueArrayMaker<std::is_trivially_destructible<T>::value, T>::ResultType;
90
91template<typename T>
92UniqueArray<T> makeUniqueArray(size_t size)
93{
94 static_assert(std::is_same<typename std::remove_extent<T>::type, T>::value, "");
95 return UniqueArrayMaker<std::is_trivially_destructible<T>::value, T>::make(size);
96}
97
98} // namespace WTF
99
100using WTF::UniqueArray;
101using WTF::makeUniqueArray;
102