Line data Source code
1 : /////////////////////////////////////////////////////////////////////////// 2 : // Spetabaru - Berenger Bramas MPCDF - 2017 3 : // Under LGPL Licence, please you must read the LICENCE file. 4 : /////////////////////////////////////////////////////////////////////////// 5 : #ifndef SPBUFFERDATAVIEW_HPP 6 : #define SPBUFFERDATAVIEW_HPP 7 : 8 : #include <atomic> 9 : 10 : #include "SpAbstractBufferManager.hpp" 11 : 12 : template <class TargetType> 13 : class SpDataBufferCore{ 14 : SpAbstractBufferManager<TargetType>* bufferManager; 15 : 16 : std::atomic<bool> underUsage; 17 : std::atomic<int> dataUseLimitCounter; 18 : std::atomic<TargetType*> dataPtr; 19 : std::atomic<int> dataUseCounter; 20 : 21 : std::atomic<int> nbOfPossibleDeleter; 22 : 23 208 : bool freeDataIfPossible(){ 24 208 : if(underUsage == false && dataUseLimitCounter == dataUseCounter){ 25 103 : TargetType* todeleteDataPtr = dataPtr; 26 103 : TargetType* nullDataptr = nullptr; 27 103 : if(todeleteDataPtr != nullptr && dataPtr.compare_exchange_strong(todeleteDataPtr, nullDataptr) == true){ 28 103 : assert(nbOfPossibleDeleter >= 1); 29 103 : while(nbOfPossibleDeleter != 1); 30 103 : if(bufferManager){ 31 102 : bufferManager->releaseABuffer(todeleteDataPtr); 32 : } 33 : else{ 34 1 : delete todeleteDataPtr; 35 : } 36 103 : delete this; 37 103 : return true; 38 : } 39 : else{ 40 0 : assert(todeleteDataPtr == nullptr); 41 : } 42 : } 43 105 : return false; 44 : } 45 : 46 103 : ~SpDataBufferCore(){ 47 103 : } 48 : 49 : public: 50 103 : explicit SpDataBufferCore(SpAbstractBufferManager<TargetType>* inBufferManager = nullptr) 51 103 : : bufferManager(inBufferManager), underUsage(true), dataUseLimitCounter(0), dataPtr(nullptr), dataUseCounter(0), nbOfPossibleDeleter(0){ 52 103 : } 53 : 54 : SpDataBufferCore(const SpDataBufferCore&) = delete; 55 : SpDataBufferCore(SpDataBufferCore&&) = delete; 56 : SpDataBufferCore& operator=(const SpDataBufferCore&) = delete; 57 : SpDataBufferCore& operator=(SpDataBufferCore&&) = delete; 58 : 59 105 : void useData(){ 60 : // Do nothing 61 105 : assert(dataUseCounter < dataUseLimitCounter); 62 105 : } 63 : 64 105 : TargetType* getData(){ 65 105 : if(dataPtr == nullptr){ 66 103 : TargetType* newDataPtr = (bufferManager ? bufferManager->getABuffer() : new TargetType()); 67 103 : TargetType* nullDataptr = nullptr; 68 103 : if(dataPtr.compare_exchange_strong(nullDataptr, newDataPtr) == false){ 69 0 : assert(nullDataptr != nullptr); 70 0 : if(bufferManager){ 71 0 : bufferManager->releaseABuffer(newDataPtr); 72 : } 73 : else{ 74 0 : delete newDataPtr; 75 : } 76 : } 77 : } 78 105 : return dataPtr; 79 : } 80 : 81 105 : void releaseData(){ 82 105 : nbOfPossibleDeleter += 1; 83 105 : assert(dataUseCounter < dataUseLimitCounter); 84 105 : dataUseCounter += 1; 85 105 : if(freeDataIfPossible() == false){ 86 6 : nbOfPossibleDeleter -= 1; 87 : } 88 105 : } 89 : 90 105 : void addOneUse(){ 91 105 : assert(underUsage); 92 105 : dataUseLimitCounter += 1; 93 105 : } 94 : 95 103 : void dataUseLimitIsFixed(){ 96 103 : nbOfPossibleDeleter += 1; 97 103 : assert(underUsage); 98 103 : underUsage = false; 99 103 : if(freeDataIfPossible() == false){ 100 99 : nbOfPossibleDeleter -= 1; 101 : } 102 103 : } 103 : }; 104 : 105 : 106 : template <class TargetType> 107 : class SpDataBuffer{ 108 : SpDataBufferCore<TargetType>* dataPtr; 109 : 110 : public: 111 105 : SpDataBuffer(SpDataBufferCore<TargetType>& inData) 112 105 : : dataPtr(&inData){ 113 105 : dataPtr->useData(); 114 105 : } 115 : 116 : SpDataBuffer(const SpDataBufferCore<TargetType>& inData) 117 : : SpDataBuffer(*const_cast<SpDataBufferCore<TargetType>*>(&inData)){ 118 : } 119 : 120 : SpDataBuffer(const SpDataBuffer&) = delete; 121 : SpDataBuffer& operator=(const SpDataBuffer&) = delete; 122 : 123 105 : ~SpDataBuffer(){ 124 105 : dataPtr->releaseData(); 125 105 : } 126 : 127 : operator TargetType&(){ 128 : return *dataPtr->getData(); 129 : } 130 : 131 : operator const TargetType&() const{ 132 : return *dataPtr->getData(); 133 : } 134 : 135 : TargetType* operator->(){ 136 : return dataPtr->getData(); 137 : } 138 : 139 : const TargetType* operator->() const{ 140 : return dataPtr->getData(); 141 : } 142 : 143 105 : TargetType& operator*(){ 144 105 : return *dataPtr->getData(); 145 : } 146 : 147 : const TargetType& operator*() const{ 148 : return *dataPtr->getData(); 149 : } 150 : }; 151 : 152 : template <class TargetType> 153 : class SpBufferDataView{ 154 : SpDataBufferCore<TargetType>* dataPtr; 155 : 156 : public: 157 103 : explicit SpBufferDataView(SpAbstractBufferManager<TargetType>* inBufferManager = nullptr){ 158 103 : dataPtr = new SpDataBufferCore<TargetType>(inBufferManager); 159 103 : } 160 : 161 : SpBufferDataView(SpBufferDataView&&) = default; 162 : 163 : SpBufferDataView(const SpBufferDataView&) = delete; 164 : SpBufferDataView& operator=(const SpBufferDataView&) = delete; 165 : SpBufferDataView& operator=(SpBufferDataView&&) = delete; 166 : 167 103 : ~SpBufferDataView(){ 168 103 : dataPtr->dataUseLimitIsFixed(); 169 103 : } 170 : 171 : // Must be called only when passed to a task 172 105 : SpDataBufferCore<TargetType>& getDataDep(){ 173 105 : dataPtr->addOneUse(); 174 105 : return *dataPtr; 175 : } 176 : }; 177 : 178 : #endif