// David Eberly, Geometric Tools, Redmond WA 98052 // Copyright (c) 1998-2020 // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt // Version: 4.0.2019.08.13 #pragma once #include #include // The Array3 class represents a 3-dimensional array that minimizes the number // of new and delete calls. The T objects are stored in a contiguous array. namespace WwiseGTE { template class Array3 { public: // Construction. The first constructor generates an array of objects // that are owned by Array3. The second constructor is given an array // of objects that are owned by the caller. The array has bound0 // columns, bound1 rows, and bound2 slices. Array3(size_t bound0, size_t bound1, size_t bound2) : mBound0(bound0), mBound1(bound1), mBound2(bound2), mObjects(bound0 * bound1 * bound2), mIndirect1(bound1 * bound2), mIndirect2(bound2) { SetPointers(mObjects.data()); } Array3(size_t bound0, size_t bound1, size_t bound2, T* objects) : mBound0(bound0), mBound1(bound1), mBound2(bound2), mIndirect1(bound1 * bound2), mIndirect2(bound2) { SetPointers(objects); } // Support for dynamic resizing, copying, or moving. If 'other' does // not own the original 'objects', they are not copied by the // assignment operator. Array3() : mBound0(0), mBound1(0), mBound2(0) { } Array3(Array3 const& other) : mBound0(other.mBound0), mBound1(other.mBound1), mBound2(other.mBound2) { *this = other; } Array3& operator=(Array3 const& other) { // The copy is valid whether or not other.mObjects has elements. mObjects = other.mObjects; SetPointers(other); return *this; } Array3(Array3&& other) noexcept : mBound0(other.mBound0), mBound1(other.mBound1), mBound2(other.mBound2) { *this = std::move(other); } Array3& operator=(Array3&& other) noexcept { // The move is valid whether or not other.mObjects has elements. mObjects = std::move(other.mObjects); SetPointers(other); return *this; } // Access to the array. Sample usage is // Array3 myArray(4, 3, 2); // T** slice1 = myArray[1]; // T* slice1row2 = myArray[1][2]; // T slice1Row2Col3 = myArray[1][2][3]; inline size_t GetBound0() const { return mBound0; } inline size_t GetBound1() const { return mBound1; } inline size_t GetBound2() const { return mBound2; } inline T* const* operator[](int slice) const { return mIndirect2[slice]; } inline T** operator[](int slice) { return mIndirect2[slice]; } private: void SetPointers(T* objects) { for (size_t i2 = 0; i2 < mBound2; ++i2) { size_t j1 = mBound1 * i2; // = bound1*(i2 + j2) where j2 = 0 mIndirect2[i2] = &mIndirect1[j1]; for (size_t i1 = 0; i1 < mBound1; ++i1) { size_t j0 = mBound0 * (i1 + j1); mIndirect2[i2][i1] = &objects[j0]; } } } void SetPointers(Array3 const& other) { mBound0 = other.mBound0; mBound1 = other.mBound1; mBound2 = other.mBound2; mIndirect1.resize(mBound1 * mBound2); mIndirect2.resize(mBound2); if (mBound0 > 0) { // The objects are owned. SetPointers(mObjects.data()); } else if (mIndirect1.size() > 0) { // The objects are not owned. SetPointers(other.mIndirect2[0][0]); } // else 'other' is an empty Array3. } size_t mBound0, mBound1, mBound2; std::vector mObjects; std::vector mIndirect1; std::vector mIndirect2; }; }