Merge pull request #376 from aerofly/master

MVKVector and small bug fix
diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
index d7ee478..d25f6cd 100644
--- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
+++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
@@ -9,6 +9,10 @@
 /* Begin PBXBuildFile section */
 		45003E73214AD4E500E989CB /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; };
 		45003E74214AD4E600E989CB /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; };
+		83A4AD2A21BD75570006C935 /* MVKVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A4AD2521BD75570006C935 /* MVKVector.h */; };
+		83A4AD2B21BD75570006C935 /* MVKVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A4AD2521BD75570006C935 /* MVKVector.h */; };
+		83A4AD2C21BD75570006C935 /* MVKVectorAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A4AD2921BD75570006C935 /* MVKVectorAllocator.h */; };
+		83A4AD2D21BD75570006C935 /* MVKVectorAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A4AD2921BD75570006C935 /* MVKVectorAllocator.h */; };
 		A9096E5E1F81E16300DFBEA6 /* MVKCmdDispatch.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9096E5D1F81E16300DFBEA6 /* MVKCmdDispatch.mm */; };
 		A9096E5F1F81E16300DFBEA6 /* MVKCmdDispatch.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9096E5D1F81E16300DFBEA6 /* MVKCmdDispatch.mm */; };
 		A909F65F213B190700FCD6BE /* MVKExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A909F65A213B190600FCD6BE /* MVKExtensions.h */; };
@@ -261,6 +265,8 @@
 
 /* Begin PBXFileReference section */
 		45003E6F214AD4C900E989CB /* MVKExtensions.def */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = MVKExtensions.def; sourceTree = "<group>"; };
+		83A4AD2521BD75570006C935 /* MVKVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKVector.h; sourceTree = "<group>"; };
+		83A4AD2921BD75570006C935 /* MVKVectorAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKVectorAllocator.h; sourceTree = "<group>"; };
 		A9096E5C1F81E16300DFBEA6 /* MVKCmdDispatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVKCmdDispatch.h; sourceTree = "<group>"; };
 		A9096E5D1F81E16300DFBEA6 /* MVKCmdDispatch.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKCmdDispatch.mm; sourceTree = "<group>"; };
 		A909F65A213B190600FCD6BE /* MVKExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKExtensions.h; sourceTree = "<group>"; };
@@ -491,6 +497,8 @@
 		A98149401FB6A3F7005F00B4 /* Utility */ = {
 			isa = PBXGroup;
 			children = (
+				83A4AD2521BD75570006C935 /* MVKVector.h */,
+				83A4AD2921BD75570006C935 /* MVKVectorAllocator.h */,
 				A98149411FB6A3F7005F00B4 /* MVKBaseObject.cpp */,
 				A98149421FB6A3F7005F00B4 /* MVKBaseObject.h */,
 				A98149431FB6A3F7005F00B4 /* MVKEnvironment.h */,
@@ -607,10 +615,12 @@
 				A9F042A61FB4CF83009FCCB8 /* MVKLogging.h in Headers */,
 				A94FB8001C7DFB4800632CA3 /* MVKQueue.h in Headers */,
 				A94FB7EC1C7DFB4800632CA3 /* MVKFramebuffer.h in Headers */,
+				83A4AD2C21BD75570006C935 /* MVKVectorAllocator.h in Headers */,
 				A98149611FB6A3F7005F00B4 /* MVKWatermarkShaderSource.h in Headers */,
 				A9E53DE32100B197002781DD /* MTLSamplerDescriptor+MoltenVK.h in Headers */,
 				A94FB8181C7DFB4800632CA3 /* MVKSync.h in Headers */,
 				A94FB7E41C7DFB4800632CA3 /* MVKDevice.h in Headers */,
+				83A4AD2A21BD75570006C935 /* MVKVector.h in Headers */,
 				A94FB7D41C7DFB4800632CA3 /* MVKCommandPool.h in Headers */,
 				A94FB80C1C7DFB4800632CA3 /* MVKShaderModule.h in Headers */,
 				A94FB7C01C7DFB4800632CA3 /* MVKCmdQueries.h in Headers */,
@@ -668,10 +678,12 @@
 				A9F042A71FB4CF83009FCCB8 /* MVKLogging.h in Headers */,
 				A94FB8011C7DFB4800632CA3 /* MVKQueue.h in Headers */,
 				A94FB7ED1C7DFB4800632CA3 /* MVKFramebuffer.h in Headers */,
+				83A4AD2D21BD75570006C935 /* MVKVectorAllocator.h in Headers */,
 				A98149621FB6A3F7005F00B4 /* MVKWatermarkShaderSource.h in Headers */,
 				A9E53DE42100B197002781DD /* MTLSamplerDescriptor+MoltenVK.h in Headers */,
 				A94FB8191C7DFB4800632CA3 /* MVKSync.h in Headers */,
 				A94FB7E51C7DFB4800632CA3 /* MVKDevice.h in Headers */,
+				83A4AD2B21BD75570006C935 /* MVKVector.h in Headers */,
 				A94FB7D51C7DFB4800632CA3 /* MVKCommandPool.h in Headers */,
 				A94FB80D1C7DFB4800632CA3 /* MVKShaderModule.h in Headers */,
 				A94FB7C11C7DFB4800632CA3 /* MVKCmdQueries.h in Headers */,
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h
index 91bd8b6..7e585cd 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h
@@ -20,7 +20,7 @@
 
 #include "MVKCommand.h"
 #include "MVKMTLResourceBindings.h"
-#include <vector>
+#include "MVKVector.h"
 
 #import <Metal/Metal.h>
 
@@ -44,7 +44,7 @@
     MVKCmdBindVertexBuffers(MVKCommandTypePool<MVKCmdBindVertexBuffers>* pool);
 
 protected:
-    std::vector<MVKMTLBufferBinding> _bindings;
+    MVKVector<MVKMTLBufferBinding> _bindings;
 };
 
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
index a6002f7..5689133 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
@@ -19,6 +19,7 @@
 #pragma once
 
 #include "MVKCommand.h"
+#include "MVKVector.h"
 #include <vector>
 
 class MVKCommandBuffer;
@@ -101,8 +102,8 @@
 private:
 	VkPipelineBindPoint _pipelineBindPoint;
 	MVKPipelineLayout* _pipelineLayout;
-	std::vector<MVKDescriptorSet*> _descriptorSets;
-	std::vector<uint32_t> _dynamicOffsets;
+	MVKVector<MVKDescriptorSet*> _descriptorSets;
+	MVKVector<uint32_t>          _dynamicOffsets;
 	uint32_t _firstSet;
 };
 
@@ -128,7 +129,7 @@
 	MVKPipelineLayout* _pipelineLayout;
 	VkShaderStageFlags _stageFlags;
 	uint32_t _offset;
-	std::vector<char> _pushConstants;
+	MVKVector<char> _pushConstants;
 };
 
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
index 57d1ac8..01f141c 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
@@ -160,7 +160,7 @@
 	_offset = offset;
 
 	_pushConstants.resize(size);
-	copy_n((char*)pValues, size, _pushConstants.begin());
+  std::copy_n((char*)pValues, size, _pushConstants.begin());
 }
 
 void MVKCmdPushConstants::encode(MVKCommandEncoder* cmdEncoder) {
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
index db87024..9562d6b 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
@@ -19,6 +19,7 @@
 #pragma once
 
 #include "MVKCommand.h"
+#include "MVKVector.h"
 #include <vector>
 
 #import <Metal/Metal.h>
@@ -47,7 +48,7 @@
 	VkSubpassContents _contents;
 	MVKRenderPass* _renderPass;
 	MVKFramebuffer* _framebuffer;
-	std::vector<VkClearValue> _clearValues;
+	MVKVector<VkClearValue> _clearValues;
 };
 
 
@@ -114,7 +115,7 @@
 
 private:
 	uint32_t _firstViewport;
-	std::vector<MTLViewport> _mtlViewports;
+	MVKVector<MTLViewport> _mtlViewports;
 };
 
 
@@ -133,7 +134,7 @@
 
 private:
 	uint32_t _firstScissor;
-	std::vector<MTLScissorRect> _mtlScissors;
+	MVKVector<MTLScissorRect> _mtlScissors;
 };
 
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
index 7560d4c..d970f0e 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
@@ -23,6 +23,7 @@
 #include "MVKCommandEncoderState.h"
 #include "MVKMTLBufferAllocation.h"
 #include "MVKCmdPipeline.h"
+#include "MVKVector.h"
 #include <vector>
 #include <unordered_map>
 
@@ -239,7 +240,7 @@
 						 MVKRenderPass* renderPass,
 						 MVKFramebuffer* framebuffer,
 						 VkRect2D& renderArea,
-						 std::vector<VkClearValue>* clearValues);
+						 MVKVector<VkClearValue>* clearValues);
 
 	/** Begins the next render subpass. */
 	void beginNextSubpass(VkSubpassContents renderpassContents);
@@ -402,7 +403,7 @@
 	uint32_t _renderSubpassIndex;
 	VkRect2D _renderArea;
     MVKActivatedQueries* _pActivatedQueries;
-	std::vector<VkClearValue> _clearValues;
+	MVKVector<VkClearValue> _clearValues;
 	id<MTLComputeCommandEncoder> _mtlComputeEncoder;
 	MVKCommandUse _mtlComputeEncoderUse;
 	id<MTLBlitCommandEncoder> _mtlBlitEncoder;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
index 35ebe11..d36819b 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
@@ -219,7 +219,7 @@
 										MVKRenderPass* renderPass,
 										MVKFramebuffer* framebuffer,
 										VkRect2D& renderArea,
-										vector<VkClearValue>* clearValues) {
+										MVKVector<VkClearValue>* clearValues) {
 	_renderPass = renderPass;
 	_framebuffer = framebuffer;
 	_renderArea = renderArea;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
index 4981e65..a87a7e0 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
@@ -18,9 +18,9 @@
 
 #pragma once
 
-#include  "MVKMTLResourceBindings.h"
+#include "MVKMTLResourceBindings.h"
 #include "MVKCommandResourceFactory.h"
-#include <vector>
+#include "MVKVector.h"
 
 class MVKCommandEncoder;
 class MVKOcclusionQueryPool;
@@ -135,7 +135,7 @@
 	 * The isSettingDynamically indicates that the scissor is being changed dynamically,
 	 * which is only allowed if the pipeline was created as VK_DYNAMIC_STATE_SCISSOR.
 	 */
-	void setViewports(std::vector<MTLViewport> mtlViewports,
+	void setViewports(const MVKVector<MTLViewport> &mtlViewports,
 					  uint32_t firstViewport,
 					  bool isSettingDynamically);
 
@@ -147,7 +147,7 @@
     void encodeImpl() override;
     void resetImpl() override;
 
-    std::vector<MTLViewport> _mtlViewports;
+    MVKVector<MTLViewport> _mtlViewports;
 };
 
 
@@ -164,7 +164,7 @@
 	 * The isSettingDynamically indicates that the scissor is being changed dynamically,
 	 * which is only allowed if the pipeline was created as VK_DYNAMIC_STATE_SCISSOR.
 	 */
-	void setScissors(std::vector<MTLScissorRect> mtlScissors,
+	void setScissors(const MVKVector<MTLScissorRect> &mtlScissors,
 					 uint32_t firstScissor,
 					 bool isSettingDynamically);
 
@@ -176,7 +176,7 @@
     void encodeImpl() override;
     void resetImpl() override;
 
-    std::vector<MTLScissorRect> _mtlScissors;
+    MVKVector<MTLScissorRect> _mtlScissors;
 };
 
 
@@ -189,7 +189,7 @@
 public:
 
     /** Sets the specified push constants. */
-    void setPushConstants(uint32_t offset, std::vector<char>& pushConstants);
+    void setPushConstants(uint32_t offset, MVKVector<char>& pushConstants);
 
     /** Sets the index of the Metal buffer used to hold the push constants. */
     void setMTLBufferIndex(uint32_t mtlBufferIndex);
@@ -203,7 +203,7 @@
     void encodeImpl() override;
     void resetImpl() override;
 
-    std::vector<char> _pushConstants;
+    MVKVector<char> _pushConstants;
     VkShaderStageFlagBits _shaderStage;
     uint32_t _mtlBufferIndex = 0;
 };
@@ -348,15 +348,15 @@
 
     // Template function that marks both the vector and all binding elements in the vector as dirty.
     template<class T>
-    void markDirty(std::vector<T>& bindings, bool& bindingsDirtyFlag) {
+    void markDirty(T& bindings, bool& bindingsDirtyFlag) {
         for (auto& b : bindings) { b.isDirty = true; }
         bindingsDirtyFlag = true;
     }
 
     // Template function that updates an existing binding or adds a new binding to a vector
     // of bindings, and marks the binding, the vector, and this instance as dirty
-    template<class T>
-    void bind(const T& b, std::vector<T>& bindings, bool& bindingsDirtyFlag) {
+    template<class T, class U>
+    void bind(const T& b, U& bindings, bool& bindingsDirtyFlag) {
 
         if ( !b.mtlResource ) { return; }
 
@@ -365,7 +365,7 @@
         bindingsDirtyFlag = true;
         db.isDirty = true;
 
-        for (auto iter = bindings.begin(), end = bindings.end(); iter != end; iter++) {
+        for (auto iter = bindings.begin(), end = bindings.end(); iter != end; ++iter) {
             if( iter->index == db.index ) {
                 *iter = db;
                 return;
@@ -377,7 +377,7 @@
     // Template function that executes a lambda expression on each dirty element of
     // a vector of bindings, and marks the bindings and the vector as no longer dirty.
     template<class T>
-    void encodeBinding(std::vector<T>& bindings,
+    void encodeBinding(MVKVector<T>& bindings,
                        bool& bindingsDirtyFlag,
                        std::function<void(MVKCommandEncoder* cmdEncoder, T& b)> mtlOperation) {
         if (bindingsDirtyFlag) {
@@ -451,12 +451,12 @@
     void resetImpl() override;
     void markDirty() override;
 
-    std::vector<MVKMTLBufferBinding> _vertexBufferBindings;
-    std::vector<MVKMTLBufferBinding> _fragmentBufferBindings;
-    std::vector<MVKMTLTextureBinding> _vertexTextureBindings;
-    std::vector<MVKMTLTextureBinding> _fragmentTextureBindings;
-    std::vector<MVKMTLSamplerStateBinding> _vertexSamplerStateBindings;
-    std::vector<MVKMTLSamplerStateBinding> _fragmentSamplerStateBindings;
+    MVKVector<MVKMTLBufferBinding> _vertexBufferBindings;
+    MVKVector<MVKMTLBufferBinding> _fragmentBufferBindings;
+    MVKVector<MVKMTLTextureBinding> _vertexTextureBindings;
+    MVKVector<MVKMTLTextureBinding> _fragmentTextureBindings;
+    MVKVector<MVKMTLSamplerStateBinding> _vertexSamplerStateBindings;
+    MVKVector<MVKMTLSamplerStateBinding> _fragmentSamplerStateBindings;
     MVKMTLBufferBinding _vertexAuxBufferBinding;
     MVKMTLBufferBinding _fragmentAuxBufferBinding;
 
@@ -499,9 +499,9 @@
     void resetImpl() override;
     void markDirty() override;
 
-    std::vector<MVKMTLBufferBinding> _bufferBindings;
-    std::vector<MVKMTLTextureBinding> _textureBindings;
-    std::vector<MVKMTLSamplerStateBinding> _samplerStateBindings;
+    MVKVector<MVKMTLBufferBinding> _bufferBindings;
+    MVKVector<MVKMTLTextureBinding> _textureBindings;
+    MVKVector<MVKMTLSamplerStateBinding> _samplerStateBindings;
     MVKMTLBufferBinding _auxBufferBinding;
 
     bool _areBufferBindingsDirty = false;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
index b1ed8f3..f50843f 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
@@ -50,7 +50,7 @@
 #pragma mark -
 #pragma mark MVKViewportCommandEncoderState
 
-void MVKViewportCommandEncoderState::setViewports(vector<MTLViewport> mtlViewports,
+void MVKViewportCommandEncoderState::setViewports(const MVKVector<MTLViewport> &mtlViewports,
 												  uint32_t firstViewport,
 												  bool isSettingDynamically) {
 
@@ -91,7 +91,7 @@
 #pragma mark -
 #pragma mark MVKScissorCommandEncoderState
 
-void MVKScissorCommandEncoderState::setScissors(vector<MTLScissorRect> mtlScissors,
+void MVKScissorCommandEncoderState::setScissors(const MVKVector<MTLScissorRect> &mtlScissors,
                                                 uint32_t firstScissor,
 												bool isSettingDynamically) {
 
@@ -113,7 +113,7 @@
 
 void MVKScissorCommandEncoderState::encodeImpl() {
 	MVKAssert(!_mtlScissors.empty(), "Must specify at least one scissor rect");
-	std::vector<MTLScissorRect> clippedScissors(_mtlScissors);
+	auto clippedScissors(_mtlScissors);
 	std::for_each(clippedScissors.begin(), clippedScissors.end(), [this](MTLScissorRect& scissor) {
 		scissor = _cmdEncoder->clipToRenderArea(scissor);
 	});
@@ -136,7 +136,7 @@
 #pragma mark -
 #pragma mark MVKPushConstantsCommandEncoderState
 
-void MVKPushConstantsCommandEncoderState:: setPushConstants(uint32_t offset, vector<char>& pushConstants) {
+void MVKPushConstantsCommandEncoderState:: setPushConstants(uint32_t offset, MVKVector<char>& pushConstants) {
     uint32_t pcCnt = (uint32_t)pushConstants.size();
     mvkEnsureSize(_pushConstants, offset + pcCnt);
     copy(pushConstants.begin(), pushConstants.end(), _pushConstants.begin() + offset);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index 865fb00..47ce94a 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -20,6 +20,7 @@
 
 #include "MVKDevice.h"
 #include "MVKImage.h"
+#include "MVKVector.h"
 #include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
 #include <unordered_set>
 #include <unordered_map>
@@ -80,7 +81,7 @@
     void bind(MVKCommandEncoder* cmdEncoder,
               MVKDescriptorBinding& descBinding,
               MVKShaderResourceBinding& dslMTLRezIdxOffsets,
-              std::vector<uint32_t>& dynamicOffsets,
+              MVKVector<uint32_t>& dynamicOffsets,
               uint32_t* pDynamicOffsetIndex);
 
     /** Encodes this binding layout and the specified descriptor binding on the specified command encoder immediately. */
@@ -131,7 +132,7 @@
     void bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
                            MVKDescriptorSet* descSet,
                            MVKShaderResourceBinding& dslMTLRezIdxOffsets,
-                           std::vector<uint32_t>& dynamicOffsets,
+                           MVKVector<uint32_t>& dynamicOffsets,
                            uint32_t* pDynamicOffsetIndex);
 
 
@@ -165,7 +166,7 @@
 	friend class MVKPipelineLayout;
 	friend class MVKDescriptorSet;
 
-	std::vector<MVKDescriptorSetLayoutBinding> _bindings;
+	MVKVector<MVKDescriptorSetLayoutBinding> _bindings;
 	std::unordered_map<uint32_t, uint32_t> _bindingToIndex;
 	MVKShaderResourceBinding _mtlResourceCounts;
 	bool _isPushDescriptorLayout : 1;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index d9bd60e..0cd71f3 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -80,7 +80,7 @@
 void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
                                          MVKDescriptorBinding& descBinding,
                                          MVKShaderResourceBinding& dslMTLRezIdxOffsets,
-                                         vector<uint32_t>& dynamicOffsets,
+                                         MVKVector<uint32_t>& dynamicOffsets,
                                          uint32_t* pDynamicOffsetIndex) {
     MVKMTLBufferBinding bb;
     MVKMTLTextureBinding tb;
@@ -494,7 +494,7 @@
 void MVKDescriptorSetLayout::bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
                                                MVKDescriptorSet* descSet,
                                                MVKShaderResourceBinding& dslMTLRezIdxOffsets,
-                                               vector<uint32_t>& dynamicOffsets,
+                                               MVKVector<uint32_t>& dynamicOffsets,
                                                uint32_t* pDynamicOffsetIndex) {
 
     if (_isPushDescriptorLayout) return;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
index 3e3f246..4761825 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
@@ -22,6 +22,7 @@
 #include "MVKDescriptorSet.h"
 #include "MVKShaderModule.h"
 #include "MVKSync.h"
+#include "MVKVector.h"
 #include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
 #include <unordered_set>
 #include <vector>
@@ -53,9 +54,9 @@
 
 	/** Binds descriptor sets to a command encoder. */
     void bindDescriptorSets(MVKCommandEncoder* cmdEncoder,
-                            std::vector<MVKDescriptorSet*>& descriptorSets,
+                            MVKVector<MVKDescriptorSet*>& descriptorSets,
                             uint32_t firstSet,
-                            std::vector<uint32_t>& dynamicOffsets);
+                            MVKVector<uint32_t>& dynamicOffsets);
 
 	/** Populates the specified shader converter context. */
 	void populateShaderConverterContext(SPIRVToMSLConverterContext& context);
@@ -157,8 +158,8 @@
 	VkPipelineRasterizationStateCreateInfo _rasterInfo;
 	VkPipelineDepthStencilStateCreateInfo _depthStencilInfo;
 
-    std::vector<MTLViewport> _mtlViewports;
-	std::vector<MTLScissorRect> _mtlScissors;
+  MVKVector<MTLViewport> _mtlViewports;
+  MVKVector<MTLScissorRect> _mtlScissors;
 
 	id<MTLRenderPipelineState> _mtlPipelineState;
 	MTLCullMode _mtlCullMode;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index 271f5a5..74c496b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -36,9 +36,9 @@
 #pragma mark MVKPipelineLayout
 
 void MVKPipelineLayout::bindDescriptorSets(MVKCommandEncoder* cmdEncoder,
-                                           vector<MVKDescriptorSet*>& descriptorSets,
+                                           MVKVector<MVKDescriptorSet*>& descriptorSets,
                                            uint32_t firstSet,
-                                           vector<uint32_t>& dynamicOffsets) {
+                                           MVKVector<uint32_t>& dynamicOffsets) {
 
 	uint32_t pDynamicOffsetIndex = 0;
 	uint32_t dsCnt = (uint32_t)descriptorSets.size();
@@ -342,7 +342,11 @@
 		}
 	}
 
-	// Fragment shader - only add if rasterization is enabled
+  // bug fix by aerofly -> if no fragment shader is used and _needsFragmentAuxBuffer was true newBufferWithLength was trying to allocate zero bytes
+  // please verify this fix
+  _needsFragmentAuxBuffer = false;
+
+  // Fragment shader - only add if rasterization is enabled
 	for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
 		const VkPipelineShaderStageCreateInfo* pSS = &pCreateInfo->pStages[i];
 		if (mvkAreFlagsEnabled(pSS->stage, VK_SHADER_STAGE_FRAGMENT_BIT) && !shaderContext.options.isRasterizationDisabled) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
index c27d7d2..d3e6a2f 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
@@ -22,6 +22,7 @@
 #include "MVKCommandBuffer.h"
 #include "MVKImage.h"
 #include "MVKSync.h"
+#include "MVKVector.h"
 #include <vector>
 #include <mutex>
 
@@ -169,7 +170,7 @@
 	MVKQueueSubmission* _prev;
 	MVKQueueSubmission* _next;
 	VkResult _submissionResult;
-	std::vector<MVKSemaphore*> _waitSemaphores;
+	MVKVector<MVKSemaphore*> _waitSemaphores;
 	bool _isAwaitingSemaphores;
 };
 
@@ -204,8 +205,8 @@
 	void commitActiveMTLCommandBuffer(bool signalCompletion = false);
 	void finish();
 
-	std::vector<MVKCommandBuffer*> _cmdBuffers;
-	std::vector<MVKSemaphore*> _signalSemaphores;
+	MVKVector<MVKCommandBuffer*> _cmdBuffers;
+	MVKVector<MVKSemaphore*> _signalSemaphores;
 	MVKFence* _fence;
     MVKCommandUse _cmdBuffUse;
 	id<MTLCommandBuffer> _activeMTLCommandBuffer;
@@ -227,6 +228,6 @@
 									 const VkPresentInfoKHR* pPresentInfo);
 
 protected:
-	std::vector<MVKSwapchainImage*> _surfaceImages;
+	MVKVector<MVKSwapchainImage*> _surfaceImages;
 };
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
index 7449550..34cbea6 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
@@ -19,6 +19,7 @@
 #pragma once
 
 #include "MVKDevice.h"
+#include "MVKVector.h"
 #include <vector>
 
 #import <Metal/Metal.h>
@@ -56,7 +57,7 @@
 	 */
 	void populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
 										 MVKFramebuffer* framebuffer,
-										 std::vector<VkClearValue>& clearValues,
+										 MVKVector<VkClearValue>& clearValues,
 										 bool isRenderingEntireAttachment);
 
 	/**
@@ -64,7 +65,7 @@
 	 * when the render area is smaller than the full framebuffer size.
 	 */
 	void populateClearAttachments(std::vector<VkClearAttachment>& clearAtts,
-								  std::vector<VkClearValue>& clearValues);
+								  MVKVector<VkClearValue>& clearValues);
 
 	/** Constructs an instance for the specified parent renderpass. */
 	MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription* pCreateInfo);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
index 0a63201..b695ba5 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
@@ -67,7 +67,7 @@
 
 void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
 													   MVKFramebuffer* framebuffer,
-													   vector<VkClearValue>& clearValues,
+													   MVKVector<VkClearValue>& clearValues,
 													   bool isRenderingEntireAttachment) {
 	// Populate the Metal color attachments
 	uint32_t caCnt = getColorAttachmentCount();
@@ -157,7 +157,7 @@
 }
 
 void MVKRenderSubpass::populateClearAttachments(vector<VkClearAttachment>& clearAtts,
-												vector<VkClearValue>& clearValues) {
+												MVKVector<VkClearValue>& clearValues) {
 	VkClearAttachment cAtt;
 
 	uint32_t attIdx;
diff --git a/MoltenVK/MoltenVK/Utility/MVKVector.h b/MoltenVK/MoltenVK/Utility/MVKVector.h
new file mode 100755
index 0000000..df0b8a9
--- /dev/null
+++ b/MoltenVK/MoltenVK/Utility/MVKVector.h
@@ -0,0 +1,528 @@
+/*

+ * MVKVectorAllocator.h

+ *

+ * Copyright (c) 2012-2018 Dr. Torsten Hans (hans@ipacs.de)

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ * 

+ *     http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+#pragma once

+

+//

+// in case MVKVector should use std::vector

+//

+#if 0

+

+template<typename T>

+using MVKVector = std::vector<T>;

+

+#else

+

+//

+// a simple std::vector like container with a configurable extra stack space

+// this class supports just the necessary members to be compatible with MoltenVK

+// if C++17 is used, code can be simplified further

+// by default MVKVector used 8 elements from the stack before getting memory from heap

+//

+#include "MVKVectorAllocator.h"

+#include <type_traits>

+#include <initializer_list>

+#include <utility>

+

+template<class Type, class Allocator = mvk_vector_allocator_with_stack<Type, 8>> class MVKVector

+{

+  Allocator alc;

+

+public:

+  class iterator

+  {

+    const MVKVector *vector;

+    size_t           index;

+

+  public:

+    iterator() = delete;

+    iterator( const size_t _index, const MVKVector &_vector ) : vector{ &_vector }, index{ _index } { }

+

+    iterator &operator=( const iterator &it )

+    {

+      vector = it.vector;

+      index = it.index;

+      return *this;

+    }

+

+    Type *operator->() const

+    {

+      return &vector->alc.ptr[index];

+    }

+

+    Type &operator*() const

+    {

+      return vector->alc.ptr[index];

+    }

+

+    operator Type*() const

+    {

+      return &vector->alc.ptr[index];

+    }

+

+    bool operator==( const iterator &it ) const

+    {

+      return ( vector == it.vector ) && ( index == it.index );

+    }

+

+    bool operator!=( const iterator &it ) const

+    {

+      return ( vector != it.vector ) || ( index != it.index );

+    }

+

+    iterator& operator++() { ++index; return *this; }

+

+    bool   is_valid()     const { return index < vector->alc.num_elements_used; }

+    size_t get_position() const { return index; }

+  };

+

+  class reverse_iterator

+  {

+    const MVKVector *vector;

+    size_t           index;

+

+  public:

+    reverse_iterator() = delete;

+    reverse_iterator( const size_t _index, const MVKVector &_vector ) : vector{ &_vector }, index{ _index } { }

+    reverse_iterator &operator=( const reverse_iterator & ) = delete;

+

+    Type *operator->() const

+    {

+      return &vector->alc.ptr[index];

+    }

+

+    Type &operator*() const

+    {

+      return vector->alc.ptr[index];

+    }

+

+    operator Type*() const

+    {

+      return &vector->alc.ptr[index];

+    }

+    

+    bool operator==( const reverse_iterator &it ) const

+    {

+      return vector == it.vector && index == it.index;

+    }

+

+    bool operator!=( const reverse_iterator &it ) const

+    {

+      return vector != it.vector || index != it.index;

+    }

+

+    reverse_iterator& operator++() { --index; return *this; }

+

+    bool   is_valid()     const { return index < vector->alc.num_elements_used; }

+    size_t get_position() const { return index; }

+  };

+

+private:

+  size_t vector_GetNextCapacity() const

+  {

+    constexpr auto ELEMENTS_FOR_64_BYTES = 64 / sizeof( Type );

+    constexpr auto MINIMUM_CAPACITY = ELEMENTS_FOR_64_BYTES > 4 ? ELEMENTS_FOR_64_BYTES : 4;

+    const auto current_capacity = capacity();

+    //if( current_capacity < 256 )

+    //  return MINIMUM_CAPACITY + 2 * current_capacity;

+    return MINIMUM_CAPACITY + ( 3 * current_capacity ) / 2;

+  }

+

+  void vector_Allocate( const size_t s )

+  {

+    const auto new_reserved_size = tm_max( s, alc.num_elements_used );

+

+    alc.allocate( new_reserved_size );

+  }

+

+  void vector_ReAllocate( const size_t s )

+  {

+    alc.re_allocate( s );

+  }

+

+public:

+  MVKVector()

+  {

+  }

+

+  MVKVector( const size_t n, const Type t )

+  {

+    if( n > 0 )

+    {

+      alc.allocate( n );

+

+      for( size_t i = 0; i < n; ++i )

+      {

+        alc.construct( &alc.ptr[i], t );

+      }

+

+      alc.num_elements_used = n;

+    }

+  }

+

+  MVKVector( const MVKVector &a )

+  {

+    const size_t n = a.size();

+

+    if( n > 0 )

+    {

+      alc.allocate( n );

+

+      for( size_t i = 0; i < n; ++i )

+      {

+        alc.construct( &alc.ptr[i], a.alc.ptr[i] );

+      }

+

+      alc.num_elements_used = n;

+    }

+  }

+

+  MVKVector( MVKVector &&a ) : alc{ std::move( a.alc ) }

+  {

+  }

+

+  MVKVector( std::initializer_list<Type> vector )

+  {

+    if( vector.size() > capacity() )

+    {

+      vector_Allocate( vector.size() );

+    }

+

+    // std::initializer_list does not yet support std::move, we use it anyway but it has no effect

+    for( auto &&element : vector )

+    {

+      alc.construct( &alc.ptr[alc.num_elements_used], std::move( element ) );

+      ++alc.num_elements_used;

+    }

+  }

+

+  ~MVKVector()

+  {

+  }

+

+  MVKVector& operator=( const MVKVector &a )

+  {

+    if( this != &a )

+    {

+      const auto n = a.alc.num_elements_used;

+

+      if( alc.num_elements_used == n )

+      {

+        for( size_t i = 0; i < n; ++i )

+        {

+          alc.ptr[i] = a.alc.ptr[i];

+        }

+      }

+      else

+      {

+        if( n > capacity() )

+        {

+          vector_ReAllocate( n );

+        }

+        else

+        {

+          alc.template destruct_all<Type>();

+        }

+

+        for( size_t i = 0; i < n; ++i )

+        {

+          alc.construct( &alc.ptr[i], a.alc.ptr[i] );

+        }

+

+        alc.num_elements_used = n;

+      }

+    }

+

+    return *this;

+  }

+

+  MVKVector& operator=( MVKVector &&a )

+  {

+    alc.swap( a.alc );

+    return *this;

+  }

+

+  bool operator==( const MVKVector &a ) const

+  {

+    if( alc.num_elements_used != a.alc.num_elements_used )

+      return false;

+    for( size_t i = 0; i < alc.num_elements_used; ++i )

+    {

+      if( alc.ptr[i] != a.alc.ptr[i] )

+        return false;

+    }

+    return true;

+  }

+

+  bool operator!=( const MVKVector &a ) const

+  {

+    if( alc.num_elements_used != a.alc.num_elements_used )

+      return true;

+    for( size_t i = 0; i < alc.num_elements_used; ++i )

+    {

+      if( alc.ptr[i] != a.alc.ptr[i] )

+        return true;

+    }

+    return false;

+  }

+

+  void swap( MVKVector &a )

+  {

+    alc.swap( a.alc );

+  }

+

+  void clear()

+  {

+    alc.template destruct_all<Type>();

+  }

+

+  void reset()

+  {

+    alc.deallocate();

+  }

+

+  iterator         begin()  const { return iterator( 0, *this ); }

+  iterator         end()    const { return iterator( alc.num_elements_used, *this ); }

+  reverse_iterator rbegin() const { return reverse_iterator( alc.num_elements_used - 1, *this ); }

+  reverse_iterator rend()   const { return reverse_iterator( size_t( -1 ), *this ); }

+  size_t           size()   const { return alc.num_elements_used; }

+  bool             empty()  const { return alc.num_elements_used == 0; }

+

+  Type &at( const size_t i ) const

+  {

+    return alc.ptr[i];

+  }

+

+  const Type &operator[]( const size_t i ) const

+  {

+    return alc.ptr[i];

+  }

+

+  Type &operator[]( const size_t i )

+  {

+    return alc.ptr[i];

+  }

+

+  const Type *data() const

+  {

+    return alc.ptr;

+  }

+

+  Type *data()

+  {

+    return alc.ptr;

+  }

+

+  size_t capacity() const

+  {

+    return alc.get_capacity();

+  }

+

+  const Type &front() const

+  {

+    return alc.ptr[0];

+  }

+

+  Type &front()

+  {

+    return alc.ptr[0];

+  }

+

+  const Type &back() const

+  {

+    return alc.ptr[alc.num_elements_used - 1];

+  }

+

+  Type &back()

+  {

+    return alc.ptr[alc.num_elements_used - 1];

+  }

+

+  void pop_back()

+  {

+    if( alc.num_elements_used > 0 )

+    {

+      --alc.num_elements_used;

+      alc.destruct( &alc.ptr[alc.num_elements_used] );

+    }

+  }

+

+  void reserve( const size_t new_size )

+  {

+    if( new_size > capacity() )

+    {

+      vector_ReAllocate( new_size );

+    }

+  }

+

+  void assign( const size_t new_size, const Type &t )

+  {

+    if( new_size <= capacity() )

+    {

+      clear();

+    }

+    else

+    {

+      vector_Allocate( new_size );

+    }

+

+    for( size_t i = 0; i < new_size; ++i )

+    {

+      alc.construct( &alc.ptr[i], t );

+    }

+

+    alc.num_elements_used = new_size;

+  }

+

+  template <class InputIterator>

+  void assign( InputIterator first, InputIterator last )

+  {

+    clear();

+    

+    while( first != last )

+    {

+      emplace_back( *first );

+      ++first;

+    }

+  }

+

+  void resize( const size_t new_size, const Type t = { } )

+  {

+    if( new_size == alc.num_elements_used )

+    {

+      return;

+    }

+

+    if( new_size == 0 )

+    {

+      clear();

+      return;

+    }

+

+    if( new_size > alc.num_elements_used )

+    {

+      if( new_size > capacity() )

+      {

+        vector_ReAllocate( new_size );

+      }

+

+      while( alc.num_elements_used < new_size )

+      {

+        alc.construct( &alc.ptr[alc.num_elements_used], t );

+        ++alc.num_elements_used;

+      }

+    }

+    else

+    {

+      //if constexpr( !std::is_trivially_destructible<Type>::value )

+      {

+        while( alc.num_elements_used > new_size )

+        {

+          --alc.num_elements_used;

+          alc.destruct( &alc.ptr[alc.num_elements_used] );

+        }

+      }

+      //else

+      //{

+      //  alc.num_elements_used = new_size;

+      //}

+    }

+  }

+

+  // trims the capacity of the slist to the number of alc.ptr

+  void shrink_to_fit()

+  {

+    alc.shrink_to_fit();

+  }

+

+  void erase( const iterator it )

+  {

+    if( it.is_valid() )

+    {

+      --alc.num_elements_used;

+

+      for( size_t i = it.GetIndex(); i < alc.num_elements_used; ++i )

+      {

+        alc.ptr[i] = std::move( alc.ptr[i + 1] );

+      }

+

+      // this is required for types with a destructor

+      alc.destruct( &alc.ptr[alc.num_elements_used] );

+    }

+  }

+

+  // adds t before it and automatically resizes vector if necessary

+  void insert( const iterator it, Type t )

+  {

+    if( !it.is_valid() || alc.num_elements_used == 0 )

+    {

+      push_back( std::move( t ) );

+    }

+    else

+    {

+      if( alc.num_elements_used == capacity() )

+        vector_ReAllocate( vector_GetNextCapacity() );

+

+      // move construct last element

+      alc.construct( &alc.ptr[alc.num_elements_used], std::move( alc.ptr[alc.num_elements_used - 1] ) );

+

+      // move the remaining elements

+      const size_t it_position = it.get_position();

+      for( size_t i = alc.num_elements_used - 1; i > it_position; --i )

+      {

+        alc.ptr[i] = std::move( alc.ptr[i - 1] );

+      }

+

+      alc.ptr[it_position] = std::move( t );

+      ++alc.num_elements_used;

+    }

+  }

+

+  void push_back( const Type &t )

+  {

+    if( alc.num_elements_used == capacity() )

+      vector_ReAllocate( vector_GetNextCapacity() );

+

+    alc.construct( &alc.ptr[alc.num_elements_used], t );

+    ++alc.num_elements_used;

+  }

+

+  void push_back( Type &&t )

+  {

+    if( alc.num_elements_used == capacity() )

+      vector_ReAllocate( vector_GetNextCapacity() );

+

+    alc.construct( &alc.ptr[alc.num_elements_used], std::forward<Type>( t ) );

+    ++alc.num_elements_used;

+  }

+

+  template<class... Args>

+  Type &emplace_back( Args&&... args )

+  {

+    if( alc.num_elements_used == capacity() )

+      vector_ReAllocate( vector_GetNextCapacity() );

+

+    alc.construct( &alc.ptr[alc.num_elements_used], std::forward<Args>( args )... );

+    ++alc.num_elements_used;

+

+    return alc.ptr[alc.num_elements_used - 1];

+  }

+};

+

+#endif

+

diff --git a/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h b/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h
new file mode 100755
index 0000000..442e0ac
--- /dev/null
+++ b/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h
@@ -0,0 +1,526 @@
+/*

+ * MVKVectorAllocator.h

+ *

+ * Copyright (c) 2012-2018 Dr. Torsten Hans (hans@ipacs.de)

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ * 

+ *     http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+#pragma once

+

+#include <new>

+#include <type_traits>

+

+namespace mvk_memory_allocator

+{

+  inline char *alloc( const size_t num_bytes )

+  {

+    return new char[num_bytes];

+  }

+

+  inline void free( void *ptr )

+  {

+    delete[] (char*)ptr;

+  }

+};

+

+

+//////////////////////////////////////////////////////////////////////////////////////////

+//

+// mvk_vector_allocator_default -> malloc based allocator for MVKVector

+//

+//////////////////////////////////////////////////////////////////////////////////////////

+template <typename T>

+class mvk_vector_allocator_default final

+{

+public:

+  T      *ptr;

+  size_t  num_elements_used;

+

+private:

+  size_t  num_elements_reserved;

+

+public:

+  template<class S, class... Args> typename std::enable_if< !std::is_trivially_constructible<S>::value >::type

+    construct( S *_ptr, Args&&... _args )

+  {

+    new ( _ptr ) S( std::forward<Args>( _args )... );

+  }

+

+  template<class S, class... Args> typename std::enable_if< std::is_trivially_constructible<S>::value >::type

+    construct( S *_ptr, Args&&... _args )

+  {

+    *_ptr = S( std::forward<Args>( _args )... );

+  }

+

+  template<class S> typename std::enable_if< !std::is_trivially_destructible<S>::value >::type

+    destruct( S *_ptr )

+  {

+    _ptr->~S();

+  }

+

+  template<class S> typename std::enable_if< std::is_trivially_destructible<S>::value >::type

+    destruct( S *_ptr )

+  {

+  }

+

+  template<class S> typename std::enable_if< !std::is_trivially_destructible<S>::value >::type

+    destruct_all()

+  {

+    for( size_t i = 0; i < num_elements_used; ++i )

+    {

+      ptr[i].~S();

+    }

+

+    num_elements_used = 0;

+  }

+

+  template<class S> typename std::enable_if< std::is_trivially_destructible<S>::value >::type

+    destruct_all()

+  {

+    num_elements_used = 0;

+  }

+

+public:

+  constexpr mvk_vector_allocator_default() : ptr{ nullptr }, num_elements_used{ 0 }, num_elements_reserved{ 0 }

+  {

+  }

+

+  mvk_vector_allocator_default( mvk_vector_allocator_default &&a ) : ptr{ a.ptr }, num_elements_used{ a.num_elements_used }, num_elements_reserved{ a.num_elements_reserved }

+  {

+    a.ptr = nullptr;

+    a.num_elements_used = 0;

+    a.num_elements_reserved = 0;

+  }

+

+  ~mvk_vector_allocator_default()

+  {

+    deallocate();

+  }

+

+  size_t get_capacity() const

+  {

+    return num_elements_reserved;

+  }

+

+  void swap( mvk_vector_allocator_default &a )

+  {

+    const auto copy_ptr                   = a.ptr;

+    const auto copy_num_elements_used     = a.num_elements_used;

+    const auto copy_num_elements_reserved = a.num_elements_reserved;

+

+    a.ptr                   = ptr;

+    a.num_elements_used     = num_elements_used;

+    a.num_elements_reserved = num_elements_reserved;

+

+    ptr                   = copy_ptr;

+    num_elements_used     = copy_num_elements_used;

+    num_elements_reserved = copy_num_elements_reserved;

+  }

+

+  void allocate( const size_t num_elements_to_reserve )

+  {

+    deallocate();

+

+    ptr                   = reinterpret_cast< T* >( mvk_memory_allocator::alloc( num_elements_to_reserve * sizeof( T ) ) );

+    num_elements_used     = 0;

+    num_elements_reserved = num_elements_to_reserve;

+  }

+

+  void re_allocate( const size_t num_elements_to_reserve )

+  {

+    //if constexpr( std::is_trivially_copyable<T>::value )

+    //{

+    //  ptr = reinterpret_cast< T* >( mvk_memory_allocator::tm_memrealloc( ptr, num_elements_to_reserve * sizeof( T ) );

+    //}

+    //else

+    {

+      auto *new_ptr = reinterpret_cast< T* >( mvk_memory_allocator::alloc( num_elements_to_reserve * sizeof( T ) ) );

+

+      for( size_t i = 0; i < num_elements_used; ++i )

+      {

+        construct( &new_ptr[i], std::move( ptr[i] ) );

+        destruct( &ptr[i] );

+      }

+

+      //if ( ptr != nullptr )

+      {

+        mvk_memory_allocator::free( ptr );

+      }

+

+      ptr = new_ptr;

+    }

+

+    num_elements_reserved = num_elements_to_reserve;

+  }

+

+  void shrink_to_fit()

+  {

+    if( num_elements_used == 0 )

+    {

+      deallocate();

+    }

+    else

+    {

+      auto *new_ptr = reinterpret_cast< T* >( mvk_memory_allocator::alloc( num_elements_used * sizeof( T ) ) );

+

+      for( size_t i = 0; i < num_elements_used; ++i )

+      {

+        construct( &new_ptr[i], std::move( ptr[i] ) );

+        destruct( &ptr[i] );

+      }

+

+      mvk_memory_allocator::free( ptr );

+

+      ptr = new_ptr;

+      num_elements_reserved = num_elements_used;

+    }

+  }

+

+  void deallocate()

+  {

+    destruct_all<T>();

+

+    mvk_memory_allocator::free( ptr );

+

+    ptr = nullptr;

+    num_elements_reserved = 0;

+  }

+};

+

+

+//////////////////////////////////////////////////////////////////////////////////////////

+//

+// mvk_vector_allocator_with_stack -> malloc based MVKVector allocator with stack storage

+//

+//////////////////////////////////////////////////////////////////////////////////////////

+template <typename T, int N>

+class mvk_vector_allocator_with_stack

+{

+public:

+  T      *ptr;

+  size_t  num_elements_used;

+

+private:

+  //size_t  num_elements_reserved; // uhh, num_elements_reserved is mapped onto the stack elements, let the fun begin

+  alignas( alignof( T ) ) unsigned char   elements_stack[N * sizeof( T )];

+

+  static_assert( N * sizeof( T ) >= sizeof( size_t ), "Bummer, nasty optimization doesn't work" );

+

+  void set_num_elements_reserved( const size_t num_elements_reserved )

+  {

+    *reinterpret_cast< size_t* >( &elements_stack[0] ) = num_elements_reserved;

+  }

+

+

+public:

+  //

+  // faster element construction and destruction using type traits

+  //

+  template<class S, class... Args> typename std::enable_if< !std::is_trivially_constructible<S, Args...>::value >::type

+    construct( S *_ptr, Args&&... _args )

+  {

+    new ( _ptr ) S( std::forward<Args>( _args )... );

+  }

+

+  template<class S, class... Args> typename std::enable_if< std::is_trivially_constructible<S, Args...>::value >::type

+    construct( S *_ptr, Args&&... _args )

+  {

+    *_ptr = S( std::forward<Args>( _args )... );

+  }

+

+  template<class S> typename std::enable_if< !std::is_trivially_destructible<S>::value >::type

+    destruct( S *_ptr )

+  {

+    _ptr->~S();

+  }

+

+  template<class S> typename std::enable_if< std::is_trivially_destructible<S>::value >::type

+    destruct( S *_ptr )

+  {

+  }

+

+  template<class S> typename std::enable_if< !std::is_trivially_destructible<S>::value >::type

+    destruct_all()

+  {

+    for( size_t i = 0; i < num_elements_used; ++i )

+    {

+      ptr[i].~S();

+    }

+

+    num_elements_used = 0;

+  }

+

+  template<class S> typename std::enable_if< std::is_trivially_destructible<S>::value >::type

+    destruct_all()

+  {

+    num_elements_used = 0;

+  }

+

+  template<class S> typename std::enable_if< !std::is_trivially_destructible<S>::value >::type

+    swap_stack( mvk_vector_allocator_with_stack &a )

+  {

+    T stack_copy[N];

+

+    for( size_t i = 0; i < num_elements_used; ++i )

+    {

+      construct( &stack_copy[i], std::move( ptr[i] ) );

+      destruct( &ptr[i] );

+    }

+

+    for( size_t i = 0; i < a.num_elements_used; ++i )

+    {

+      construct( &ptr[i], std::move( a.ptr[i] ) );

+      destruct( &ptr[i] );

+    }

+

+    for( size_t i = 0; i < num_elements_used; ++i )

+    {

+      construct( &a.ptr[i], std::move( stack_copy[i] ) );

+      destruct( &stack_copy[i] );

+    }

+  }

+

+  template<class S> typename std::enable_if< std::is_trivially_destructible<S>::value >::type

+    swap_stack( mvk_vector_allocator_with_stack &a )

+  {

+    constexpr int STACK_SIZE = N * sizeof( T );

+    for( int i = 0; i < STACK_SIZE; ++i )

+    {

+      const auto v = elements_stack[i];

+      elements_stack[i] = a.elements_stack[i];

+      a.elements_stack[i] = v;

+    }

+  }

+

+public:

+  mvk_vector_allocator_with_stack() : ptr{ reinterpret_cast< T* >( &elements_stack[0] ) }, num_elements_used{ 0 }

+  {

+  }

+

+  mvk_vector_allocator_with_stack( mvk_vector_allocator_with_stack &&a ) : num_elements_used{ a.num_elements_used }

+  {

+    // is a heap based -> steal ptr from a

+    if( !a.get_data_on_stack() )

+    {

+      ptr = a.ptr;

+      set_num_elements_reserved( a.get_capacity() );

+

+      a.ptr = a.get_default_ptr();

+    }

+    else

+    {

+      ptr = get_default_ptr();

+      for( size_t i = 0; i < a.num_elements_used; ++i )

+      {

+        construct( &ptr[i], std::move( a.ptr[i] ) );

+        destruct( &a.ptr[i] );

+      }

+    }

+

+    a.num_elements_used = 0;

+  }

+

+  ~mvk_vector_allocator_with_stack()

+  {

+    deallocate();

+  }

+

+  size_t get_capacity() const

+  {

+    return get_data_on_stack() ? N : *reinterpret_cast< const size_t* >( &elements_stack[0] );

+  }

+

+  constexpr T *get_default_ptr() const

+  {

+    return reinterpret_cast< T* >( const_cast< unsigned char * >( &elements_stack[0] ) );

+  }

+

+  bool get_data_on_stack() const

+  {

+    return ptr == get_default_ptr();

+  }

+

+  void swap( mvk_vector_allocator_with_stack &a )

+  {

+    // both allocators on heap -> easy case

+    if( !get_data_on_stack() && !a.get_data_on_stack() )

+    {

+      auto copy_ptr = ptr;

+      auto copy_num_elements_reserved = get_capacity();

+      ptr = a.ptr;

+      set_num_elements_reserved( a.get_capacity() );

+      a.ptr = copy_ptr;

+      a.set_num_elements_reserved( copy_num_elements_reserved );

+    }

+    // both allocators on stack -> just switch the stack contents

+    else if( get_data_on_stack() && a.get_data_on_stack() )

+    {

+      swap_stack<T>( a );

+    }

+    else if( get_data_on_stack() && !a.get_data_on_stack() )

+    {

+      auto copy_ptr = a.ptr;

+      auto copy_num_elements_reserved = a.get_capacity();

+

+      a.ptr = a.get_default_ptr();

+      for( size_t i = 0; i < num_elements_used; ++i )

+      {

+        construct( &a.ptr[i], std::move( ptr[i] ) );

+        destruct( &ptr[i] );

+      }

+

+      ptr = copy_ptr;

+      set_num_elements_reserved( copy_num_elements_reserved );

+    }

+    else if( !get_data_on_stack() && a.get_data_on_stack() )

+    {

+      auto copy_ptr = ptr;

+      auto copy_num_elements_reserved = get_capacity();

+

+      ptr = get_default_ptr();

+      for( size_t i = 0; i < a.num_elements_used; ++i )

+      {

+        construct( &ptr[i], std::move( a.ptr[i] ) );

+        destruct( &a.ptr[i] );

+      }

+

+      a.ptr = copy_ptr;

+      a.set_num_elements_reserved( copy_num_elements_reserved );

+    }

+

+    auto copy_num_elements_used = num_elements_used;

+    num_elements_used = a.num_elements_used;

+    a.num_elements_used = copy_num_elements_used;

+  }

+

+  //

+  // allocates rounded up to the defined alignment the number of bytes / if the system cannot allocate the specified amount of memory then a null block is returned

+  //

+  void allocate( const size_t num_elements_to_reserve )

+  {

+    deallocate();

+

+    // check if enough memory on stack space is left

+    if( num_elements_to_reserve <= N )

+    {

+      return;

+    }

+

+    ptr               = reinterpret_cast< T* >( mvk_memory_allocator::alloc( num_elements_to_reserve * sizeof( T ) ) );

+    num_elements_used = 0;

+    set_num_elements_reserved( num_elements_to_reserve );

+  }

+

+  //template<class S> typename std::enable_if< !std::is_trivially_copyable<S>::value >::type

+  void _re_allocate( const size_t num_elements_to_reserve )

+  {

+    auto *new_ptr = reinterpret_cast< T* >( mvk_memory_allocator::alloc( num_elements_to_reserve * sizeof( T ) ) );

+

+    for( size_t i = 0; i < num_elements_used; ++i )

+    {

+      construct( &new_ptr[i], std::move( ptr[i] ) );

+      destruct( &ptr[i] );

+    }

+

+    if( ptr != get_default_ptr() )

+    {

+      mvk_memory_allocator::free( ptr );

+    }

+

+    ptr = new_ptr;

+    set_num_elements_reserved( num_elements_to_reserve );

+  }

+

+  //template<class S> typename std::enable_if< std::is_trivially_copyable<S>::value >::type

+  //  _re_allocate( const size_t num_elements_to_reserve )

+  //{

+  //  const bool data_is_on_stack = get_data_on_stack();

+  //

+  //  auto *new_ptr = reinterpret_cast< S* >( mvk_memory_allocator::tm_memrealloc( data_is_on_stack ? nullptr : ptr, num_elements_to_reserve * sizeof( S ) ) );

+  //  if( data_is_on_stack )

+  //  {

+  //    for( int i = 0; i < N; ++i )

+  //    {

+  //      new_ptr[i] = ptr[i];

+  //    }

+  //  }

+  //

+  //  ptr = new_ptr;

+  //  set_num_elements_reserved( num_elements_to_reserve );

+  //}

+

+  void re_allocate( const size_t num_elements_to_reserve )

+  {

+    //TM_ASSERT( num_elements_to_reserve > get_capacity() );

+

+    if( num_elements_to_reserve > N )

+    {

+      _re_allocate( num_elements_to_reserve );

+    }

+  }

+

+  void shrink_to_fit()

+  {

+    // nothing to do if data is on stack already

+    if( get_data_on_stack() )

+      return;

+

+    // move elements to stack space

+    if( num_elements_used <= N )

+    {

+      const auto num_elements_reserved = get_capacity();

+

+      auto *stack_ptr = get_default_ptr();

+      for( size_t i = 0; i < num_elements_used; ++i )

+      {

+        construct( &stack_ptr[i], std::move( ptr[i] ) );

+        destruct( &ptr[i] );

+      }

+

+      mvk_memory_allocator::free( ptr );

+

+      ptr = stack_ptr;

+    }

+    else

+    {

+      auto *new_ptr = reinterpret_cast< T* >( mvk_memory_allocator::alloc( ptr, num_elements_used * sizeof( T ) ) );

+

+      for( size_t i = 0; i < num_elements_used; ++i )

+      {

+        construct( &new_ptr[i], std::move( ptr[i] ) );

+        destruct( &ptr[i] );

+      }

+

+      mvk_memory_allocator::free( ptr );

+

+      ptr = new_ptr;

+      set_num_elements_reserved( num_elements_used );

+    }

+  }

+

+  void deallocate()

+  {

+    destruct_all<T>();

+

+    if( !get_data_on_stack() )

+    {

+      mvk_memory_allocator::free( ptr );

+    }

+

+    ptr = get_default_ptr();

+    num_elements_used = 0;

+  }

+};

+

+