// // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2013 LunarG, Inc. // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // // Neither the name of 3Dlabs Inc. Ltd. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // // Implement types for tracking GLSL arrays, arrays of arrays, etc. // #ifndef _ARRAYS_INCLUDED #define _ARRAYS_INCLUDED #include namespace glslang { // This is used to mean there is no size yet (unsized), it is waiting to get a size from somewhere else. const int UnsizedArraySize = 0; class TIntermTyped; extern bool SameSpecializationConstants(TIntermTyped*, TIntermTyped*); // Specialization constants need both a nominal size and a node that defines // the specialization constant being used. Array types are the same when their // size and specialization constant nodes are the same. struct TArraySize { unsigned int size; TIntermTyped* node; // nullptr means no specialization constant node bool operator==(const TArraySize& rhs) const { if (size != rhs.size) return false; if (node == nullptr || rhs.node == nullptr) return node == rhs.node; return SameSpecializationConstants(node, rhs.node); } }; // // TSmallArrayVector is used as the container for the set of sizes in TArraySizes. // It has generic-container semantics, while TArraySizes has array-of-array semantics. // That is, TSmallArrayVector should be more focused on mechanism and TArraySizes on policy. // struct TSmallArrayVector { // // TODO: memory: TSmallArrayVector is intended to be smaller. // Almost all arrays could be handled by two sizes each fitting // in 16 bits, needing a real vector only in the cases where there // are more than 3 sizes or a size needing more than 16 bits. // POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) TSmallArrayVector() : sizes(nullptr) { } virtual ~TSmallArrayVector() { dealloc(); } // For breaking into two non-shared copies, independently modifiable. TSmallArrayVector& operator=(const TSmallArrayVector& from) { if (from.sizes == nullptr) sizes = nullptr; else { alloc(); *sizes = *from.sizes; } return *this; } int size() const { if (sizes == nullptr) return 0; return (int)sizes->size(); } unsigned int frontSize() const { assert(sizes != nullptr && sizes->size() > 0); return sizes->front().size; } TIntermTyped* frontNode() const { assert(sizes != nullptr && sizes->size() > 0); return sizes->front().node; } void changeFront(unsigned int s) { assert(sizes != nullptr); // this should only happen for implicitly sized arrays, not specialization constants assert(sizes->front().node == nullptr); sizes->front().size = s; } void push_back(unsigned int e, TIntermTyped* n) { alloc(); TArraySize pair = { e, n }; sizes->push_back(pair); } void push_back(const TSmallArrayVector& newDims) { alloc(); sizes->insert(sizes->end(), newDims.sizes->begin(), newDims.sizes->end()); } void pop_front() { assert(sizes != nullptr && sizes->size() > 0); if (sizes->size() == 1) dealloc(); else sizes->erase(sizes->begin()); } // 'this' should currently not be holding anything, and copyNonFront // will make it hold a copy of all but the first element of rhs. // (This would be useful for making a type that is dereferenced by // one dimension.) void copyNonFront(const TSmallArrayVector& rhs) { assert(sizes == nullptr); if (rhs.size() > 1) { alloc(); sizes->insert(sizes->begin(), rhs.sizes->begin() + 1, rhs.sizes->end()); } } unsigned int getDimSize(int i) const { assert(sizes != nullptr && (int)sizes->size() > i); return (*sizes)[i].size; } void setDimSize(int i, unsigned int size) const { assert(sizes != nullptr && (int)sizes->size() > i); assert((*sizes)[i].node == nullptr); (*sizes)[i].size = size; } TIntermTyped* getDimNode(int i) const { assert(sizes != nullptr && (int)sizes->size() > i); return (*sizes)[i].node; } bool operator==(const TSmallArrayVector& rhs) const { if (sizes == nullptr && rhs.sizes == nullptr) return true; if (sizes == nullptr || rhs.sizes == nullptr) return false; return *sizes == *rhs.sizes; } bool operator!=(const TSmallArrayVector& rhs) const { return ! operator==(rhs); } protected: TSmallArrayVector(const TSmallArrayVector&); void alloc() { if (sizes == nullptr) sizes = new TVector; } void dealloc() { delete sizes; sizes = nullptr; } TVector* sizes; // will either hold such a pointer, or in the future, hold the two array sizes }; // // Represent an array, or array of arrays, to arbitrary depth. This is not // done through a hierarchy of types in a type tree, rather all contiguous arrayness // in the type hierarchy is localized into this single cumulative object. // // The arrayness in TTtype is a pointer, so that it can be non-allocated and zero // for the vast majority of types that are non-array types. // // Order Policy: these are all identical: // - left to right order within a contiguous set of ...[..][..][..]... in the source language // - index order 0, 1, 2, ... within the 'sizes' member below // - outer-most to inner-most // struct TArraySizes { POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) TArraySizes() : implicitArraySize(1), variablyIndexed(false) { } // For breaking into two non-shared copies, independently modifiable. TArraySizes& operator=(const TArraySizes& from) { implicitArraySize = from.implicitArraySize; variablyIndexed = from.variablyIndexed; sizes = from.sizes; return *this; } // translate from array-of-array semantics to container semantics int getNumDims() const { return sizes.size(); } int getDimSize(int dim) const { return sizes.getDimSize(dim); } TIntermTyped* getDimNode(int dim) const { return sizes.getDimNode(dim); } void setDimSize(int dim, int size) { sizes.setDimSize(dim, size); } int getOuterSize() const { return sizes.frontSize(); } TIntermTyped* getOuterNode() const { return sizes.frontNode(); } int getCumulativeSize() const { int size = 1; for (int d = 0; d < sizes.size(); ++d) { // this only makes sense in paths that have a known array size assert(sizes.getDimSize(d) != UnsizedArraySize); size *= sizes.getDimSize(d); } return size; } void addInnerSize() { addInnerSize((unsigned)UnsizedArraySize); } void addInnerSize(int s) { addInnerSize((unsigned)s, nullptr); } void addInnerSize(int s, TIntermTyped* n) { sizes.push_back((unsigned)s, n); } void addInnerSize(TArraySize pair) { sizes.push_back(pair.size, pair.node); } void addInnerSizes(const TArraySizes& s) { sizes.push_back(s.sizes); } void changeOuterSize(int s) { sizes.changeFront((unsigned)s); } int getImplicitSize() const { return implicitArraySize; } void updateImplicitSize(int s) { implicitArraySize = std::max(implicitArraySize, s); } bool isInnerUnsized() const { for (int d = 1; d < sizes.size(); ++d) { if (sizes.getDimSize(d) == (unsigned)UnsizedArraySize) return true; } return false; } bool clearInnerUnsized() { for (int d = 1; d < sizes.size(); ++d) { if (sizes.getDimSize(d) == (unsigned)UnsizedArraySize) setDimSize(d, 1); } return false; } bool isInnerSpecialization() const { for (int d = 1; d < sizes.size(); ++d) { if (sizes.getDimNode(d) != nullptr) return true; } return false; } bool isOuterSpecialization() { return sizes.getDimNode(0) != nullptr; } bool hasUnsized() const { return getOuterSize() == UnsizedArraySize || isInnerUnsized(); } bool isSized() const { return getOuterSize() != UnsizedArraySize; } void dereference() { sizes.pop_front(); } void copyDereferenced(const TArraySizes& rhs) { assert(sizes.size() == 0); if (rhs.sizes.size() > 1) sizes.copyNonFront(rhs.sizes); } bool sameInnerArrayness(const TArraySizes& rhs) const { if (sizes.size() != rhs.sizes.size()) return false; for (int d = 1; d < sizes.size(); ++d) { if (sizes.getDimSize(d) != rhs.sizes.getDimSize(d) || sizes.getDimNode(d) != rhs.sizes.getDimNode(d)) return false; } return true; } void setVariablyIndexed() { variablyIndexed = true; } bool isVariablyIndexed() const { return variablyIndexed; } bool operator==(const TArraySizes& rhs) const { return sizes == rhs.sizes; } bool operator!=(const TArraySizes& rhs) const { return sizes != rhs.sizes; } protected: TSmallArrayVector sizes; TArraySizes(const TArraySizes&); // For tracking maximum referenced compile-time constant index. // Applies only to the outer-most dimension. Potentially becomes // the implicit size of the array, if not variably indexed and // otherwise legal. int implicitArraySize; bool variablyIndexed; // true if array is indexed with a non compile-time constant }; } // end namespace glslang #endif // _ARRAYS_INCLUDED_