DenFrame2DReader.hpp 11.5 KB
Newer Older
kulvait's avatar
CTIOL  
kulvait committed
1 2 3
#pragma once

// External
kulvait's avatar
kulvait committed
4
#include <mutex>
5
#include <string>
kulvait's avatar
CTIOL  
kulvait committed
6 7

// Internal
kulvait's avatar
kulvait committed
8 9 10 11
#include "BufferedFrame2D.hpp"
#include "DEN/DenFileInfo.hpp"
#include "Frame2DI.hpp"
#include "Frame2DReaderI.hpp"
kulvait's avatar
CTIOL  
kulvait committed
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

namespace CTL {
namespace io {
    /**
     * Implementation of the ProjectionReader for projections and projection matrices stored in the
     * den files.
     */
    template <typename T>
    class DenFrame2DReader : virtual public Frame2DReaderI<T>
    // Frame2DReaderI<T> will be only once in the family tree
    {

    public:
        /**Constructs DenFrame2DReader from file name.
         *
kulvait's avatar
kulvait committed
27 28 29 30 31
         *
         * @param denFile
         * @param denFile File in a DEN format to read by frames.
         * @param additionalBufferNum Number of additional buffers to allocate. Defaults to 0 for 1
         * default buffer.
kulvait's avatar
CTIOL  
kulvait committed
32
         */
kulvait's avatar
kulvait committed
33
        DenFrame2DReader(std::string denFile, uint32_t additionalBufferNum = 0);
kulvait's avatar
CTIOL  
kulvait committed
34 35 36 37
        /// Destructor
        ~DenFrame2DReader();
        /// Copy constructor
        DenFrame2DReader(const DenFrame2DReader<T>& b);
kulvait's avatar
kulvait committed
38 39 40
        // Copy assignment with copy and swap
        DenFrame2DReader<T>& operator=(DenFrame2DReader<T> b);
        static void swap(DenFrame2DReader<T>& a, DenFrame2DReader<T>& b);
kulvait's avatar
CTIOL  
kulvait committed
41 42 43 44
        // Move constructor
        DenFrame2DReader(DenFrame2DReader<T>&& b);
        // Move assignment
        DenFrame2DReader<T>& operator=(DenFrame2DReader<T>&& other);
45 46
        std::shared_ptr<io::Frame2DI<T>> readFrame(unsigned int i) override;
        std::shared_ptr<io::BufferedFrame2D<T>> readBufferedFrame(unsigned int i);
kulvait's avatar
kulvait committed
47 48 49 50
        void readFrameIntoBuffer(unsigned int frameID, T* outside_buffer);
        uint32_t dimx() const override;
        uint32_t dimy() const override;
        uint32_t dimz() const override;
kulvait's avatar
CTIOL  
kulvait committed
51 52
        std::string getFileName() const;
        /**Returns file name of the underlying DEN file.**/
kulvait's avatar
kulvait committed
53
	protected:
kulvait's avatar
kulvait committed
54 55 56 57 58 59
        std::string denFile;
        uint64_t offset;
        // protected: // Visible in inheritance structure
        uint32_t sizex, sizey, sizez;
        DenSupportedType dataType;
        int elementByteSize;
kulvait's avatar
kulvait committed
60
    private:
kulvait's avatar
kulvait committed
61 62 63 64
        mutable std::mutex* consistencyMutexes;
        uint8_t** buffers;
        T** buffer_copys;
        uint32_t additionalBufferNum;
kulvait's avatar
CTIOL  
kulvait committed
65 66 67
    };

    template <typename T>
kulvait's avatar
kulvait committed
68 69 70
    DenFrame2DReader<T>::DenFrame2DReader(std::string denFile, uint32_t additionalBufferNum)
        : denFile(denFile)
        , additionalBufferNum(additionalBufferNum)
kulvait's avatar
CTIOL  
kulvait committed
71 72
    {
        DenFileInfo pi = DenFileInfo(this->denFile);
kulvait's avatar
kulvait committed
73
        this->offset = pi.getOffset();
74 75
        this->sizex = pi.dimx();
        this->sizey = pi.dimy();
kulvait's avatar
kulvait committed
76
        this->sizez = pi.dimz();
kulvait's avatar
CTIOL  
kulvait committed
77 78
        this->dataType = pi.getDataType();
        this->elementByteSize = pi.elementByteSize();
kulvait's avatar
kulvait committed
79 80 81 82 83 84 85 86
        this->consistencyMutexes = new std::mutex[1 + additionalBufferNum];
        this->buffers = new uint8_t*[1 + additionalBufferNum];
        this->buffer_copys = new T*[1 + additionalBufferNum];
        for(uint32_t i = 0; i != 1 + additionalBufferNum; i++)
        {
            this->buffers[i] = new uint8_t[elementByteSize * sizex * sizey];
            this->buffer_copys[i] = new T[sizex * sizey];
        }
kulvait's avatar
CTIOL  
kulvait committed
87 88 89 90 91 92 93 94 95 96
        // Buffers are used for the alocation of new frames. Since this class uses the instance that
        // copies memory, this memory might me reused.
    }

    // This mumbo jumbo is for correctly deleting object after move assignment operation was
    // performed to be able to delete such object with stealed internals where its buffers are
    // nullptr.
    template <typename T>
    DenFrame2DReader<T>::~DenFrame2DReader()
    {
kulvait's avatar
kulvait committed
97 98 99 100 101 102
        if(consistencyMutexes != nullptr)
        {
            delete[] consistencyMutexes;
        }
        consistencyMutexes = nullptr;
        if(buffers != nullptr)
kulvait's avatar
CTIOL  
kulvait committed
103
        {
kulvait's avatar
kulvait committed
104 105 106 107 108 109 110 111 112
            for(uint32_t i = 0; i != 1 + additionalBufferNum; i++)
            {
                if(buffers[i] != nullptr)
                {
                    delete buffers[i];
                }
                buffers[i] = nullptr;
            }
            delete[] buffers;
kulvait's avatar
CTIOL  
kulvait committed
113
        }
kulvait's avatar
kulvait committed
114 115
        buffers = nullptr;
        if(buffer_copys != nullptr)
kulvait's avatar
CTIOL  
kulvait committed
116
        {
kulvait's avatar
kulvait committed
117 118 119 120 121 122 123 124 125
            for(uint32_t i = 0; i != 1 + additionalBufferNum; i++)
            {
                if(buffer_copys[i] != nullptr)
                {
                    delete buffer_copys[i];
                }
                buffer_copys[i] = nullptr;
            }
            delete[] buffer_copys;
kulvait's avatar
CTIOL  
kulvait committed
126
        }
kulvait's avatar
kulvait committed
127
        buffer_copys = nullptr;
kulvait's avatar
CTIOL  
kulvait committed
128 129 130 131 132 133 134
    }

    /**Copy constructor of DenFrame2DReader from another element.
     *Basically contructs everything from scratch by probing file on the disk.
     */
    template <typename T>
    DenFrame2DReader<T>::DenFrame2DReader(const DenFrame2DReader<T>& b)
kulvait's avatar
kulvait committed
135 136 137 138 139 140
        : DenFrame2DReader<T>::DenFrame2DReader(b.denFile, b.additionalBufferNum)
    {
    }

    template <typename T>
    void DenFrame2DReader<T>::swap(DenFrame2DReader<T>& a, DenFrame2DReader<T>& b)
kulvait's avatar
CTIOL  
kulvait committed
141
    {
kulvait's avatar
kulvait committed
142 143 144 145 146 147 148 149 150 151 152 153
        std::swap(a.denFile, b.denFile);
        std::swap(a.offset, b.offset);
        std::swap(a.sizex, b.sizex);
        std::swap(a.sizey, b.sizey);
        std::swap(a.sizez, b.sizez);
        std::swap(a.dataType, b.dataType);
        std::swap(a.elementByteSize, b.elementByteSize);
        std::swap(a.additionalBufferNum, b.additionalBufferNum);
        // It will probably work just to swap pointers to the starts of respective arrays
        std::swap(a.buffers, b.buffers);
        std::swap(a.buffer_copys, b.buffer_coppys);
        std::swap(a.consistencyMutexes, b.consistencyMutexes);
kulvait's avatar
CTIOL  
kulvait committed
154 155 156 157 158 159
    }

    /**Copy assignment
     *
     */
    template <typename T>
kulvait's avatar
kulvait committed
160
    DenFrame2DReader<T>& DenFrame2DReader<T>::operator=(DenFrame2DReader<T> b)
kulvait's avatar
CTIOL  
kulvait committed
161
    {
kulvait's avatar
kulvait committed
162
        swap(*this, b);
kulvait's avatar
CTIOL  
kulvait committed
163 164 165 166 167 168 169
        return *this;
    }

    template <typename T>
    DenFrame2DReader<T>::DenFrame2DReader(DenFrame2DReader<T>&& b)
    {
        this->denFile = b.denFile;
kulvait's avatar
kulvait committed
170
        this->offset = b.offset;
kulvait's avatar
CTIOL  
kulvait committed
171
        this->sizex = b.sizex;
172
        this->sizey = b.sizey;
kulvait's avatar
CTIOL  
kulvait committed
173 174 175
        this->sizez = b.sizez;
        this->dataType = b.dataType;
        this->elementByteSize = b.elementByteSize;
kulvait's avatar
kulvait committed
176 177 178 179
        this->additionalBufferNum = b.additionalBufferNum;
        this->consistencyMutexes = std::exchange(b.consistencyMutexes, nullptr);
        this->buffers = std::exchange(b.buffers, nullptr);
        this->buffer_copys = std::exchange(b.buffer_copys, nullptr);
kulvait's avatar
CTIOL  
kulvait committed
180 181 182
    } // Move constructor to steal resources from another object

    template <typename T>
kulvait's avatar
kulvait committed
183
    DenFrame2DReader<T>& DenFrame2DReader<T>::operator=(DenFrame2DReader<T>&& b)
kulvait's avatar
CTIOL  
kulvait committed
184
    {
kulvait's avatar
kulvait committed
185
        if(&b != this) // To elegantly solve situation when assigning to itself
kulvait's avatar
CTIOL  
kulvait committed
186
        {
kulvait's avatar
kulvait committed
187 188 189 190 191 192 193 194 195
            this->denFile = b.denFile;
            this->offset = b.offset;
            this->sizex = b.sizex;
            this->sizey = b.sizey;
            this->sizez = b.sizez;
            this->dataType = b.dataType;
            this->elementByteSize = b.elementByteSize;
            this->additionalBufferNum = b.additionalBufferNum;
            if(consistencyMutexes != nullptr)
kulvait's avatar
CTIOL  
kulvait committed
196
            {
kulvait's avatar
kulvait committed
197
                delete[] consistencyMutexes;
kulvait's avatar
CTIOL  
kulvait committed
198
            }
kulvait's avatar
kulvait committed
199 200
            consistencyMutexes = nullptr;
            if(buffers != nullptr)
kulvait's avatar
CTIOL  
kulvait committed
201
            {
kulvait's avatar
kulvait committed
202 203 204 205 206 207 208 209 210
                for(uint32_t i = 0; i != 1 + additionalBufferNum; i++)
                {
                    if(buffers[i] != nullptr)
                    {
                        delete buffers[i];
                    }
                    buffers[i] = nullptr;
                }
                delete[] buffers;
kulvait's avatar
CTIOL  
kulvait committed
211
            }
kulvait's avatar
kulvait committed
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
            buffers = nullptr;
            if(buffer_copys != nullptr)
            {
                for(uint32_t i = 0; i != 1 + additionalBufferNum; i++)
                {
                    if(buffer_copys[i] != nullptr)
                    {
                        delete buffer_copys[i];
                    }
                    buffer_copys[i] = nullptr;
                }
                delete[] buffer_copys;
            }
            buffer_copys = nullptr;
            this->consistencyMutexes = std::exchange(b.consistencyMutexes, nullptr);
            this->buffers = std::exchange(b.buffers, nullptr);
            this->buffer_copys = std::exchange(b.buffer_copys, nullptr);
kulvait's avatar
CTIOL  
kulvait committed
229 230 231 232 233 234 235 236 237 238 239
        }
        return *this;
    } // Move assignment

    template <typename T>
    std::string DenFrame2DReader<T>::getFileName() const
    {
        return this->denFile;
    }

    template <typename T>
kulvait's avatar
kulvait committed
240
    uint32_t DenFrame2DReader<T>::dimx() const
kulvait's avatar
CTIOL  
kulvait committed
241 242 243 244 245
    {
        return sizex;
    }

    template <typename T>
kulvait's avatar
kulvait committed
246
    uint32_t DenFrame2DReader<T>::dimy() const
kulvait's avatar
CTIOL  
kulvait committed
247 248 249 250 251
    {
        return sizey;
    }

    template <typename T>
kulvait's avatar
kulvait committed
252
    uint32_t DenFrame2DReader<T>::dimz() const
kulvait's avatar
CTIOL  
kulvait committed
253 254 255 256 257
    {
        return sizez;
    }

    template <typename T>
258 259 260 261 262
    std::shared_ptr<io::Frame2DI<T>> DenFrame2DReader<T>::readFrame(unsigned int sliceNum)
    {
        std::shared_ptr<Frame2DI<T>> ps = readBufferedFrame(sliceNum);
        return ps;
    }
263 264 265 266

    template <typename T>
    std::shared_ptr<io::BufferedFrame2D<T>>
    DenFrame2DReader<T>::readBufferedFrame(unsigned int sliceNum)
kulvait's avatar
CTIOL  
kulvait committed
267
    {
kulvait's avatar
kulvait committed
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
        std::unique_lock<std::mutex> l;
        bool locked = false;
        uint32_t mutexnum = 0;
        for(uint32_t i = 0; i != 1 + additionalBufferNum; i++)
        {
            l = std::unique_lock<std::mutex>(consistencyMutexes[i], std::try_to_lock);
            if(l.owns_lock())
            {
                locked = true;
                mutexnum = i;
                break;
            }
        }
        if(!locked)
        {
            l = std::unique_lock<std::mutex>(consistencyMutexes[0]);
            mutexnum = 0;
        }
kulvait's avatar
CTIOL  
kulvait committed
286 287
        // Mutex will be released as this goes out of scope.
        // To protect calling this method from another thread using the same block of memory
kulvait's avatar
kulvait committed
288 289
        uint8_t* buffer = buffers[mutexnum];
        T* buffer_copy = buffer_copys[mutexnum];
kulvait's avatar
kulvait committed
290
        uint32_t elmCount = sizex * sizey;
kulvait's avatar
kulvait committed
291 292 293
        uint64_t position = this->offset + uint64_t(sliceNum) * elementByteSize * elmCount;
        io::readBytesFrom(this->denFile, position, buffer, elementByteSize * elmCount);
        for(uint32_t a = 0; a != elmCount; a++)
kulvait's avatar
CTIOL  
kulvait committed
294 295 296
        {
            buffer_copy[a] = util::getNextElement<T>(&buffer[a * elementByteSize], dataType);
        }
297
        std::shared_ptr<BufferedFrame2D<T>> ps
kulvait's avatar
CTIOL  
kulvait committed
298 299 300
            = std::make_shared<BufferedFrame2D<T>>(buffer_copy, sizex, sizey);
        return ps;
    }
kulvait's avatar
kulvait committed
301 302 303 304

    template <typename T>
    void DenFrame2DReader<T>::readFrameIntoBuffer(unsigned int frameID, T* outside_buffer)
    {
kulvait's avatar
kulvait committed
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
        std::unique_lock<std::mutex> l;
        bool locked = false;
        uint32_t mutexnum = 0;
        for(uint32_t i = 0; i != 1 + additionalBufferNum; i++)
        {
            l = std::unique_lock<std::mutex>(consistencyMutexes[i], std::try_to_lock);
            if(l.owns_lock())
            {
                locked = true;
                mutexnum = i;
                break;
            }
        }
        if(!locked)
        {
            l = std::unique_lock<std::mutex>(consistencyMutexes[0]);
            mutexnum = 0;
        }
kulvait's avatar
kulvait committed
323 324
        // Mutex will be released as this goes out of scope.
        // To protect calling this method from another thread using the same block of memory
kulvait's avatar
kulvait committed
325
        uint8_t* buffer = buffers[mutexnum];
kulvait's avatar
kulvait committed
326
        uint32_t elmCount = sizex * sizey;
kulvait's avatar
kulvait committed
327 328 329
        uint64_t position = this->offset + uint64_t(frameID) * elementByteSize * elmCount;
        io::readBytesFrom(this->denFile, position, buffer, elementByteSize * elmCount);
        for(uint32_t a = 0; a != elmCount; a++)
kulvait's avatar
kulvait committed
330 331 332 333
        {
            outside_buffer[a] = util::getNextElement<T>(&buffer[a * elementByteSize], dataType);
        }
    }
kulvait's avatar
CTIOL  
kulvait committed
334 335
} // namespace io
} // namespace CTL