PBRT
/home/felix/UBC/projects/AdaptiveLightfieldSampling/pbrt_v2/src/core/memory.h
00001 
00002 /*
00003     pbrt source code Copyright(c) 1998-2012 Matt Pharr and Greg Humphreys.
00004 
00005     This file is part of pbrt.
00006 
00007     Redistribution and use in source and binary forms, with or without
00008     modification, are permitted provided that the following conditions are
00009     met:
00010 
00011     - Redistributions of source code must retain the above copyright
00012       notice, this list of conditions and the following disclaimer.
00013 
00014     - Redistributions in binary form must reproduce the above copyright
00015       notice, this list of conditions and the following disclaimer in the
00016       documentation and/or other materials provided with the distribution.
00017 
00018     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00019     IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00020     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00021     PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00022     HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00023     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00024     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00025     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00026     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00028     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 
00030  */
00031 
00032 #if defined(_MSC_VER)
00033 #pragma once
00034 #endif
00035 
00036 #ifndef PBRT_CORE_MEMORY_H
00037 #define PBRT_CORE_MEMORY_H
00038 
00039 // core/memory.h*
00040 #include "pbrt.h"
00041 #include "parallel.h"
00042 
00043 // Memory Declarations
00044 class ReferenceCounted {
00045 public:
00046     ReferenceCounted() { nReferences = 0; }
00047     AtomicInt32 nReferences;
00048 private:
00049     ReferenceCounted(const ReferenceCounted &);
00050     ReferenceCounted &operator=(const ReferenceCounted &);
00051 };
00052 
00053 
00054 template <typename T> class Reference {
00055 public:
00056     // Reference Public Methods
00057     Reference(T *p = NULL) {
00058         ptr = p;
00059         if (ptr) AtomicAdd(&ptr->nReferences, 1);
00060     }
00061     Reference(const Reference<T> &r) {
00062         ptr = r.ptr;
00063         if (ptr) AtomicAdd(&ptr->nReferences, 1);
00064     }
00065     Reference &operator=(const Reference<T> &r) {
00066         if (r.ptr) AtomicAdd(&r.ptr->nReferences, 1);
00067         if (ptr && AtomicAdd(&ptr->nReferences, -1) == 0) delete ptr;
00068         ptr = r.ptr;
00069         return *this;
00070     }
00071     Reference &operator=(T *p) {
00072         if (p) AtomicAdd(&p->nReferences, 1);
00073         if (ptr && AtomicAdd(&ptr->nReferences, -1) == 0) delete ptr;
00074         ptr = p;
00075         return *this;
00076     }
00077     ~Reference() {
00078         if (ptr && AtomicAdd(&ptr->nReferences, -1) == 0)
00079             delete ptr;
00080     }
00081     T *operator->() { return ptr; }
00082     const T *operator->() const { return ptr; }
00083     operator bool() const { return ptr != NULL; }
00084     const T *GetPtr() const { return ptr; }
00085 private:
00086     T *ptr;
00087 };
00088 
00089 
00090 void *AllocAligned(size_t size);
00091 template <typename T> T *AllocAligned(uint32_t count) {
00092     return (T *)AllocAligned(count * sizeof(T));
00093 }
00094 
00095 
00096 void FreeAligned(void *);
00097 class MemoryArena {
00098 public:
00099     // MemoryArena Public Methods
00100     MemoryArena(uint32_t bs = 32768) {
00101         blockSize = bs;
00102         curBlockPos = 0;
00103         currentBlock = AllocAligned<char>(blockSize);
00104     }
00105     ~MemoryArena() {
00106         FreeAligned(currentBlock);
00107         for (uint32_t i = 0; i < usedBlocks.size(); ++i)
00108             FreeAligned(usedBlocks[i]);
00109         for (uint32_t i = 0; i < availableBlocks.size(); ++i)
00110             FreeAligned(availableBlocks[i]);
00111     }
00112     void *Alloc(uint32_t sz) {
00113         // Round up _sz_ to minimum machine alignment
00114         sz = ((sz + 15) & (~15));
00115         if (curBlockPos + sz > blockSize) {
00116             // Get new block of memory for _MemoryArena_
00117             usedBlocks.push_back(currentBlock);
00118             if (availableBlocks.size() && sz <= blockSize) {
00119                 currentBlock = availableBlocks.back();
00120                 availableBlocks.pop_back();
00121             }
00122             else
00123                 currentBlock = AllocAligned<char>(max(sz, blockSize));
00124             curBlockPos = 0;
00125         }
00126         void *ret = currentBlock + curBlockPos;
00127         curBlockPos += sz;
00128         return ret;
00129     }
00130     template<typename T> T *Alloc(uint32_t count = 1) {
00131         T *ret = (T *)Alloc(count * sizeof(T));
00132         for (uint32_t i = 0; i < count; ++i)
00133             new (&ret[i]) T();
00134         return ret;
00135     }
00136     void FreeAll() {
00137         curBlockPos = 0;
00138         while (usedBlocks.size()) {
00139     #ifndef NDEBUG
00140             memset(usedBlocks.back(), 0xfa, blockSize);
00141     #endif
00142             availableBlocks.push_back(usedBlocks.back());
00143             usedBlocks.pop_back();
00144         }
00145     }
00146 private:
00147     // MemoryArena Private Data
00148     uint32_t curBlockPos, blockSize;
00149     char *currentBlock;
00150     vector<char *> usedBlocks, availableBlocks;
00151 };
00152 
00153 
00154 template <typename T, int logBlockSize> class BlockedArray {
00155 public:
00156     // BlockedArray Public Methods
00157     BlockedArray(uint32_t nu, uint32_t nv, const T *d = NULL) {
00158         uRes = nu;
00159         vRes = nv;
00160         uBlocks = RoundUp(uRes) >> logBlockSize;
00161         uint32_t nAlloc = RoundUp(uRes) * RoundUp(vRes);
00162         data = AllocAligned<T>(nAlloc);
00163         for (uint32_t i = 0; i < nAlloc; ++i)
00164             new (&data[i]) T();
00165         if (d)
00166             for (uint32_t v = 0; v < vRes; ++v)
00167                 for (uint32_t u = 0; u < uRes; ++u)
00168                     (*this)(u, v) = d[v * uRes + u];
00169     }
00170     uint32_t BlockSize() const { return 1 << logBlockSize; }
00171     uint32_t RoundUp(uint32_t x) const {
00172         return (x + BlockSize() - 1) & ~(BlockSize() - 1);
00173     }
00174     uint32_t uSize() const { return uRes; }
00175     uint32_t vSize() const { return vRes; }
00176     ~BlockedArray() {
00177         for (uint32_t i = 0; i < uRes * vRes; ++i)
00178             data[i].~T();
00179         FreeAligned(data);
00180     }
00181     uint32_t Block(uint32_t a) const { return a >> logBlockSize; }
00182     uint32_t Offset(uint32_t a) const { return (a & (BlockSize() - 1)); }
00183     T &operator()(uint32_t u, uint32_t v) {
00184         uint32_t bu = Block(u), bv = Block(v);
00185         uint32_t ou = Offset(u), ov = Offset(v);
00186         uint32_t offset = BlockSize() * BlockSize() * (uBlocks * bv + bu);
00187         offset += BlockSize() * ov + ou;
00188         return data[offset];
00189     }
00190     const T &operator()(uint32_t u, uint32_t v) const {
00191         uint32_t bu = Block(u), bv = Block(v);
00192         uint32_t ou = Offset(u), ov = Offset(v);
00193         uint32_t offset = BlockSize() * BlockSize() * (uBlocks * bv + bu);
00194         offset += BlockSize() * ov + ou;
00195         return data[offset];
00196     }
00197     void GetLinearArray(T *a) const {
00198         for (uint32_t v = 0; v < vRes; ++v)
00199             for (uint32_t u = 0; u < uRes; ++u)
00200                 *a++ = (*this)(u, v);
00201     }
00202 private:
00203     // BlockedArray Private Data
00204     T *data;
00205     uint32_t uRes, vRes, uBlocks;
00206 };
00207 
00208 
00209 
00210 #endif // PBRT_CORE_MEMORY_H