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