1 /**
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <cstdlib>
20 #include <memory>
21 #include <type_traits>
22 
23 namespace android {
24 namespace uirenderer {
25 
26 /** Manages an array of T elements, freeing the array in the destructor.
27  *  Does NOT call any constructors/destructors on T (T must be POD).
28  */
29 template <typename T,
30           typename = std::enable_if_t<std::is_trivially_default_constructible<T>::value &&
31                                       std::is_trivially_destructible<T>::value>>
32 class AutoTMalloc {
33 public:
34     /** Takes ownership of the ptr. The ptr must be a value which can be passed to std::free. */
fPtr(ptr)35     explicit AutoTMalloc(T* ptr = nullptr) : fPtr(ptr) {}
36 
37     /** Allocates space for 'count' Ts. */
AutoTMalloc(size_t count)38     explicit AutoTMalloc(size_t count) : fPtr(mallocIfCountThrowOnFail(count)) {}
39 
40     AutoTMalloc(AutoTMalloc&&) = default;
41     AutoTMalloc& operator=(AutoTMalloc&&) = default;
42 
43     /** Resize the memory area pointed to by the current ptr preserving contents. */
realloc(size_t count)44     void realloc(size_t count) { fPtr.reset(reallocIfCountThrowOnFail(count)); }
45 
46     /** Resize the memory area pointed to by the current ptr without preserving contents. */
47     T* reset(size_t count = 0) {
48         fPtr.reset(mallocIfCountThrowOnFail(count));
49         return this->get();
50     }
51 
get()52     T* get() const { return fPtr.get(); }
53 
54     operator T*() { return fPtr.get(); }
55 
56     operator const T*() const { return fPtr.get(); }
57 
58     T& operator[](int index) { return fPtr.get()[index]; }
59 
60     const T& operator[](int index) const { return fPtr.get()[index]; }
61 
62     /**
63      *  Transfer ownership of the ptr to the caller, setting the internal
64      *  pointer to NULL. Note that this differs from get(), which also returns
65      *  the pointer, but it does not transfer ownership.
66      */
release()67     T* release() { return fPtr.release(); }
68 
69 private:
70     struct FreeDeleter {
operatorFreeDeleter71         void operator()(uint8_t* p) { std::free(p); }
72     };
73     std::unique_ptr<T, FreeDeleter> fPtr;
74 
mallocIfCountThrowOnFail(size_t count)75     T* mallocIfCountThrowOnFail(size_t count) {
76         T* newPtr = nullptr;
77         if (count) {
78             newPtr = (T*)std::malloc(count * sizeof(T));
79             LOG_ALWAYS_FATAL_IF(!newPtr, "failed to malloc %zu bytes", count * sizeof(T));
80         }
81         return newPtr;
82     }
reallocIfCountThrowOnFail(size_t count)83     T* reallocIfCountThrowOnFail(size_t count) {
84         T* newPtr = nullptr;
85         if (count) {
86             newPtr = (T*)std::realloc(fPtr.release(), count * sizeof(T));
87             LOG_ALWAYS_FATAL_IF(!newPtr, "failed to realloc %zu bytes", count * sizeof(T));
88         }
89         return newPtr;
90     }
91 };
92 
93 }  // namespace uirenderer
94 }  // namespace android
95