xref: /aosp_15_r20/external/mesa3d/src/gfxstream/aemu/include/AlignedBuf.h (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright 2018 Google
3*61046927SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker  */
5*61046927SAndroid Build Coastguard Worker 
6*61046927SAndroid Build Coastguard Worker #pragma once
7*61046927SAndroid Build Coastguard Worker 
8*61046927SAndroid Build Coastguard Worker #include <stdio.h>
9*61046927SAndroid Build Coastguard Worker 
10*61046927SAndroid Build Coastguard Worker #include <algorithm>
11*61046927SAndroid Build Coastguard Worker #include <atomic>
12*61046927SAndroid Build Coastguard Worker #include <cinttypes>
13*61046927SAndroid Build Coastguard Worker #include <cstdlib>
14*61046927SAndroid Build Coastguard Worker #include <cstring>
15*61046927SAndroid Build Coastguard Worker #include <type_traits>
16*61046927SAndroid Build Coastguard Worker #include <vector>
17*61046927SAndroid Build Coastguard Worker 
18*61046927SAndroid Build Coastguard Worker #ifdef _WIN32
19*61046927SAndroid Build Coastguard Worker #include <malloc.h>
20*61046927SAndroid Build Coastguard Worker #endif
21*61046927SAndroid Build Coastguard Worker 
22*61046927SAndroid Build Coastguard Worker namespace gfxstream {
23*61046927SAndroid Build Coastguard Worker 
24*61046927SAndroid Build Coastguard Worker /**
25*61046927SAndroid Build Coastguard Worker  * Do not abuse this by using any complicated T. Use it for POD or primitives
26*61046927SAndroid Build Coastguard Worker  */
27*61046927SAndroid Build Coastguard Worker template <class T, size_t align>
28*61046927SAndroid Build Coastguard Worker class AlignedBuf {
triviallyCopyable()29*61046927SAndroid Build Coastguard Worker     constexpr static bool triviallyCopyable() {
30*61046927SAndroid Build Coastguard Worker #if (defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 4) || defined(__OLD_STD_VERSION__)
31*61046927SAndroid Build Coastguard Worker         // Older g++ doesn't support std::is_trivially_copyable.
32*61046927SAndroid Build Coastguard Worker         constexpr bool triviallyCopyable = std::has_trivial_copy_constructor<T>::value;
33*61046927SAndroid Build Coastguard Worker #else
34*61046927SAndroid Build Coastguard Worker         constexpr bool triviallyCopyable = std::is_trivially_copyable<T>::value;
35*61046927SAndroid Build Coastguard Worker #endif
36*61046927SAndroid Build Coastguard Worker         return triviallyCopyable;
37*61046927SAndroid Build Coastguard Worker     }
38*61046927SAndroid Build Coastguard Worker     static_assert(triviallyCopyable() && std::is_standard_layout<T>::value &&
39*61046927SAndroid Build Coastguard Worker                   std::is_trivially_default_constructible<T>::value);
40*61046927SAndroid Build Coastguard Worker 
41*61046927SAndroid Build Coastguard Worker    public:
AlignedBuf(size_t size)42*61046927SAndroid Build Coastguard Worker     explicit AlignedBuf(size_t size) {
43*61046927SAndroid Build Coastguard Worker         static_assert(align && ((align & (align - 1)) == 0),
44*61046927SAndroid Build Coastguard Worker                       "AlignedBuf only supports power-of-2 aligments.");
45*61046927SAndroid Build Coastguard Worker         resizeImpl(size);
46*61046927SAndroid Build Coastguard Worker     }
47*61046927SAndroid Build Coastguard Worker 
AlignedBuf(const AlignedBuf & other)48*61046927SAndroid Build Coastguard Worker     AlignedBuf(const AlignedBuf& other) : AlignedBuf(other.mSize) {
49*61046927SAndroid Build Coastguard Worker         if (other.mBuffer) {  // could have got moved out
50*61046927SAndroid Build Coastguard Worker             std::copy(other.mBuffer, other.mBuffer + other.mSize, mBuffer);
51*61046927SAndroid Build Coastguard Worker         }
52*61046927SAndroid Build Coastguard Worker     }
53*61046927SAndroid Build Coastguard Worker 
54*61046927SAndroid Build Coastguard Worker     AlignedBuf& operator=(const AlignedBuf& other) {
55*61046927SAndroid Build Coastguard Worker         if (this != &other) {
56*61046927SAndroid Build Coastguard Worker             AlignedBuf tmp(other);
57*61046927SAndroid Build Coastguard Worker             *this = std::move(tmp);
58*61046927SAndroid Build Coastguard Worker         }
59*61046927SAndroid Build Coastguard Worker         return *this;
60*61046927SAndroid Build Coastguard Worker     }
61*61046927SAndroid Build Coastguard Worker 
AlignedBuf(AlignedBuf && other)62*61046927SAndroid Build Coastguard Worker     AlignedBuf(AlignedBuf&& other) { *this = std::move(other); }
63*61046927SAndroid Build Coastguard Worker 
64*61046927SAndroid Build Coastguard Worker     AlignedBuf& operator=(AlignedBuf&& other) {
65*61046927SAndroid Build Coastguard Worker         mBuffer = other.mBuffer;
66*61046927SAndroid Build Coastguard Worker         mSize = other.mSize;
67*61046927SAndroid Build Coastguard Worker 
68*61046927SAndroid Build Coastguard Worker         other.mBuffer = nullptr;
69*61046927SAndroid Build Coastguard Worker         other.mSize = 0;
70*61046927SAndroid Build Coastguard Worker 
71*61046927SAndroid Build Coastguard Worker         return *this;
72*61046927SAndroid Build Coastguard Worker     }
73*61046927SAndroid Build Coastguard Worker 
~AlignedBuf()74*61046927SAndroid Build Coastguard Worker     ~AlignedBuf() {
75*61046927SAndroid Build Coastguard Worker         if (mBuffer) freeImpl(mBuffer);
76*61046927SAndroid Build Coastguard Worker     }  // account for getting moved out
77*61046927SAndroid Build Coastguard Worker 
resize(size_t newSize)78*61046927SAndroid Build Coastguard Worker     void resize(size_t newSize) { resizeImpl(newSize); }
79*61046927SAndroid Build Coastguard Worker 
size()80*61046927SAndroid Build Coastguard Worker     size_t size() const { return mSize; }
81*61046927SAndroid Build Coastguard Worker 
data()82*61046927SAndroid Build Coastguard Worker     T* data() { return mBuffer; }
83*61046927SAndroid Build Coastguard Worker 
84*61046927SAndroid Build Coastguard Worker     T& operator[](size_t index) { return mBuffer[index]; }
85*61046927SAndroid Build Coastguard Worker 
86*61046927SAndroid Build Coastguard Worker     const T& operator[](size_t index) const { return mBuffer[index]; }
87*61046927SAndroid Build Coastguard Worker 
88*61046927SAndroid Build Coastguard Worker     bool operator==(const AlignedBuf& other) const {
89*61046927SAndroid Build Coastguard Worker         return 0 == std::memcmp(mBuffer, other.mBuffer, sizeof(T) * std::min(mSize, other.mSize));
90*61046927SAndroid Build Coastguard Worker     }
91*61046927SAndroid Build Coastguard Worker 
92*61046927SAndroid Build Coastguard Worker    private:
getNewBuffer(size_t newSize)93*61046927SAndroid Build Coastguard Worker     T* getNewBuffer(size_t newSize) {
94*61046927SAndroid Build Coastguard Worker         if (newSize == 0) {
95*61046927SAndroid Build Coastguard Worker             return nullptr;
96*61046927SAndroid Build Coastguard Worker         }
97*61046927SAndroid Build Coastguard Worker         size_t pad = std::max(align, sizeof(T));
98*61046927SAndroid Build Coastguard Worker         size_t newSizeBytes = ((align - 1 + newSize * sizeof(T) + pad) / align) * align;
99*61046927SAndroid Build Coastguard Worker         return static_cast<T*>(reallocImpl(nullptr, newSizeBytes));
100*61046927SAndroid Build Coastguard Worker     }
101*61046927SAndroid Build Coastguard Worker 
resizeImpl(size_t newSize)102*61046927SAndroid Build Coastguard Worker     void resizeImpl(size_t newSize) {
103*61046927SAndroid Build Coastguard Worker         T* new_buffer = getNewBuffer(newSize);
104*61046927SAndroid Build Coastguard Worker         if (new_buffer && mBuffer) {
105*61046927SAndroid Build Coastguard Worker             size_t keepSize = std::min(newSize, mSize);
106*61046927SAndroid Build Coastguard Worker             std::copy(mBuffer, mBuffer + keepSize, new_buffer);
107*61046927SAndroid Build Coastguard Worker         }
108*61046927SAndroid Build Coastguard Worker         if (mBuffer) {
109*61046927SAndroid Build Coastguard Worker             freeImpl(mBuffer);
110*61046927SAndroid Build Coastguard Worker         }
111*61046927SAndroid Build Coastguard Worker         mBuffer = new_buffer;
112*61046927SAndroid Build Coastguard Worker         mSize = (new_buffer ? newSize : 0);
113*61046927SAndroid Build Coastguard Worker     }
114*61046927SAndroid Build Coastguard Worker 
reallocImpl(void * oldPtr,size_t sizeBytes)115*61046927SAndroid Build Coastguard Worker     void* reallocImpl(void* oldPtr, size_t sizeBytes) {
116*61046927SAndroid Build Coastguard Worker         if (oldPtr) {
117*61046927SAndroid Build Coastguard Worker             freeImpl(oldPtr);
118*61046927SAndroid Build Coastguard Worker         }
119*61046927SAndroid Build Coastguard Worker         // Platform aligned malloc might not behave right
120*61046927SAndroid Build Coastguard Worker         // if we give it an alignment value smaller than sizeof(void*).
121*61046927SAndroid Build Coastguard Worker         size_t actualAlign = std::max(align, sizeof(void*));
122*61046927SAndroid Build Coastguard Worker #ifdef _WIN32
123*61046927SAndroid Build Coastguard Worker         return _aligned_malloc(sizeBytes, actualAlign);
124*61046927SAndroid Build Coastguard Worker #else
125*61046927SAndroid Build Coastguard Worker         void* res;
126*61046927SAndroid Build Coastguard Worker         if (posix_memalign(&res, actualAlign, sizeBytes)) {
127*61046927SAndroid Build Coastguard Worker             fprintf(stderr, "%s: failed to alloc aligned memory\n", __func__);
128*61046927SAndroid Build Coastguard Worker             abort();
129*61046927SAndroid Build Coastguard Worker         }
130*61046927SAndroid Build Coastguard Worker         return res;
131*61046927SAndroid Build Coastguard Worker #endif
132*61046927SAndroid Build Coastguard Worker     }
133*61046927SAndroid Build Coastguard Worker 
freeImpl(void * ptr)134*61046927SAndroid Build Coastguard Worker     void freeImpl(void* ptr) {
135*61046927SAndroid Build Coastguard Worker #ifdef _WIN32
136*61046927SAndroid Build Coastguard Worker         _aligned_free(ptr);
137*61046927SAndroid Build Coastguard Worker #else
138*61046927SAndroid Build Coastguard Worker         free(ptr);
139*61046927SAndroid Build Coastguard Worker #endif
140*61046927SAndroid Build Coastguard Worker     }
141*61046927SAndroid Build Coastguard Worker 
142*61046927SAndroid Build Coastguard Worker     T* mBuffer = nullptr;
143*61046927SAndroid Build Coastguard Worker     size_t mSize = 0;
144*61046927SAndroid Build Coastguard Worker };
145*61046927SAndroid Build Coastguard Worker 
146*61046927SAndroid Build Coastguard Worker // Convenience function for aligned malloc across platforms
147*61046927SAndroid Build Coastguard Worker void* aligned_buf_alloc(size_t align, size_t size);
148*61046927SAndroid Build Coastguard Worker void aligned_buf_free(void* buf);
149*61046927SAndroid Build Coastguard Worker 
150*61046927SAndroid Build Coastguard Worker }  // namespace gfxstream
151