StringBuilder::append(makeString(...)) is inefficient
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 29 Jul 2019 20:12:25 +0000 (20:12 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 29 Jul 2019 20:12:25 +0000 (20:12 +0000)
https://bugs.webkit.org/show_bug.cgi?id=200034

Reviewed by Saam Barati.

Replace uses of StringBuilder::append(makeString(...)) with StringBuilder::flexiblAppend(...).
Where possible, also merged consecutive calls to StringBuilder::append(...) into a single call
to StringBuilder::flexiblAppend(...) to avoid unnecessary additional overflow checks and resizes.
Also where possible, replaced StringBuilder with makeString() if no branching was used during
construction.

A lot more can be done to improve the efficiency of StringBuilder use in the WHLSL code including:
- Using StringView more prevelently, especially when passing a substring to the StringBuilder.
- Passing existing StringBuilders to functions for them to use rather than returning a String and
  then appending that to another StringBuilder.
- Using custom StringTypeAdapters for generated names, rather than storing them as Strings.

* Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp:
(WebCore::WHLSL::Metal::EntryPointScaffolding::resourceHelperTypes):
(WebCore::WHLSL::Metal::EntryPointScaffolding::resourceSignature):
(WebCore::WHLSL::Metal::EntryPointScaffolding::builtInsSignature):
(WebCore::WHLSL::Metal::EntryPointScaffolding::mangledInputPath):
(WebCore::WHLSL::Metal::EntryPointScaffolding::mangledOutputPath):
(WebCore::WHLSL::Metal::EntryPointScaffolding::unpackResourcesAndNamedBuiltIns):
(WebCore::WHLSL::Metal::VertexEntryPointScaffolding::helperTypes):
(WebCore::WHLSL::Metal::VertexEntryPointScaffolding::signature):
(WebCore::WHLSL::Metal::VertexEntryPointScaffolding::unpack):
(WebCore::WHLSL::Metal::VertexEntryPointScaffolding::pack):
(WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::helperTypes):
(WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::signature):
(WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::unpack):
(WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::pack):
(WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::signature):
* Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
(WebCore::WHLSL::Metal::FunctionDeclarationWriter::visit):
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::FunctionDefinitionWriter):
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::emitLoop):
* Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp:
(WebCore::WHLSL::Metal::generateMetalCodeShared):
* Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp:
(WebCore::WHLSL::Metal::writeNativeFunction):
* Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp:
(WebCore::WHLSL::Metal::MetalTypeDeclarationWriter::visit):
(WebCore::WHLSL::Metal::TypeNamer::emitUnnamedTypeDefinition):
(WebCore::WHLSL::Metal::TypeNamer::emitNamedTypeDefinition):
(WebCore::WHLSL::Metal::TypeNamer::metalTypes):
* Modules/webgpu/WHLSL/WHLSLParser.cpp:
(WebCore::WHLSL::Types::appendNameTo):
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::logLayerInfo):
* testing/Internals.cpp:
(WebCore::Internals::ongoingLoadsDescriptions const):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247917 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLParser.cpp
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebCore/testing/Internals.cpp

index a5f3bde..b93cf60 100644 (file)
@@ -1,3 +1,59 @@
+2019-07-29  Sam Weinig  <weinig@apple.com>
+
+        StringBuilder::append(makeString(...)) is inefficient
+        https://bugs.webkit.org/show_bug.cgi?id=200034
+
+        Reviewed by Saam Barati.
+
+        Replace uses of StringBuilder::append(makeString(...)) with StringBuilder::flexiblAppend(...).
+        Where possible, also merged consecutive calls to StringBuilder::append(...) into a single call
+        to StringBuilder::flexiblAppend(...) to avoid unnecessary additional overflow checks and resizes.
+        Also where possible, replaced StringBuilder with makeString() if no branching was used during
+        construction.
+        
+        A lot more can be done to improve the efficiency of StringBuilder use in the WHLSL code including:
+        - Using StringView more prevelently, especially when passing a substring to the StringBuilder.
+        - Passing existing StringBuilders to functions for them to use rather than returning a String and 
+          then appending that to another StringBuilder.
+        - Using custom StringTypeAdapters for generated names, rather than storing them as Strings. 
+
+        * Modules/webgpu/WHLSL/Metal/WHLSLEntryPointScaffolding.cpp:
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::resourceHelperTypes):
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::resourceSignature):
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::builtInsSignature):
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::mangledInputPath):
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::mangledOutputPath):
+        (WebCore::WHLSL::Metal::EntryPointScaffolding::unpackResourcesAndNamedBuiltIns):
+        (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::helperTypes):
+        (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::signature):
+        (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::unpack):
+        (WebCore::WHLSL::Metal::VertexEntryPointScaffolding::pack):
+        (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::helperTypes):
+        (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::signature):
+        (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::unpack):
+        (WebCore::WHLSL::Metal::FragmentEntryPointScaffolding::pack):
+        (WebCore::WHLSL::Metal::ComputeEntryPointScaffolding::signature):
+        * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
+        (WebCore::WHLSL::Metal::FunctionDeclarationWriter::visit):
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::FunctionDefinitionWriter):
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::emitLoop):
+        * Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp:
+        (WebCore::WHLSL::Metal::generateMetalCodeShared):
+        * Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp:
+        (WebCore::WHLSL::Metal::writeNativeFunction):
+        * Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp:
+        (WebCore::WHLSL::Metal::MetalTypeDeclarationWriter::visit):
+        (WebCore::WHLSL::Metal::TypeNamer::emitUnnamedTypeDefinition):
+        (WebCore::WHLSL::Metal::TypeNamer::emitNamedTypeDefinition):
+        (WebCore::WHLSL::Metal::TypeNamer::metalTypes):
+        * Modules/webgpu/WHLSL/WHLSLParser.cpp:
+        (WebCore::WHLSL::Types::appendNameTo):
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::logLayerInfo):
+        * testing/Internals.cpp:
+        (WebCore::Internals::ongoingLoadsDescriptions const):
+
 2019-07-29  Megan Gardner  <megan_gardner@apple.com>
 
         Force Reveal to always lookup from menu
 2019-07-29  Megan Gardner  <megan_gardner@apple.com>
 
         Force Reveal to always lookup from menu
index 1a392d5..fc337f2 100644 (file)
@@ -143,7 +143,7 @@ String EntryPointScaffolding::resourceHelperTypes()
 {
     StringBuilder stringBuilder;
     for (size_t i = 0; i < m_layout.size(); ++i) {
 {
     StringBuilder stringBuilder;
     for (size_t i = 0; i < m_layout.size(); ++i) {
-        stringBuilder.append(makeString("struct ", m_namedBindGroups[i].structName, " {\n"));
+        stringBuilder.flexibleAppend("struct ", m_namedBindGroups[i].structName, " {\n");
         Vector<std::pair<unsigned, String>> structItems;
         for (size_t j = 0; j < m_layout[i].bindings.size(); ++j) {
             auto iterator = m_resourceMap.find(&m_layout[i].bindings[j]);
         Vector<std::pair<unsigned, String>> structItems;
         for (size_t j = 0; j < m_layout[i].bindings.size(); ++j) {
             auto iterator = m_resourceMap.find(&m_layout[i].bindings[j]);
@@ -171,7 +171,7 @@ String EntryPointScaffolding::resourceHelperTypes()
             return left.first < right.first;
         });
         for (const auto& structItem : structItems)
             return left.first < right.first;
         });
         for (const auto& structItem : structItems)
-            stringBuilder.append(makeString("    ", structItem.second, '\n'));
+            stringBuilder.flexibleAppend("    ", structItem.second, '\n');
         stringBuilder.append("};\n\n");
     }
     return stringBuilder.toString();
         stringBuilder.append("};\n\n");
     }
     return stringBuilder.toString();
@@ -187,7 +187,7 @@ Optional<String> EntryPointScaffolding::resourceSignature()
         if (i)
             stringBuilder.append(", ");
         auto& namedBindGroup = m_namedBindGroups[i];
         if (i)
             stringBuilder.append(", ");
         auto& namedBindGroup = m_namedBindGroups[i];
-        stringBuilder.append(makeString("device ", namedBindGroup.structName, "& ", namedBindGroup.variableName, " [[buffer(", namedBindGroup.argumentBufferIndex, ")]]"));
+        stringBuilder.flexibleAppend("device ", namedBindGroup.structName, "& ", namedBindGroup.variableName, " [[buffer(", namedBindGroup.argumentBufferIndex, ")]]");
     }
     return stringBuilder.toString();
 }
     }
     return stringBuilder.toString();
 }
@@ -243,7 +243,7 @@ Optional<String> EntryPointScaffolding::builtInsSignature()
         if (internalType.isNull())
             internalType = m_typeNamer.mangledNameForType(*item.unnamedType);
         auto variableName = namedBuiltIn.variableName;
         if (internalType.isNull())
             internalType = m_typeNamer.mangledNameForType(*item.unnamedType);
         auto variableName = namedBuiltIn.variableName;
-        stringBuilder.append(makeString(internalType, ' ', variableName, ' ', attributeForSemantic(builtInSemantic)));
+        stringBuilder.flexibleAppend(internalType, ' ', variableName, ' ', attributeForSemantic(builtInSemantic));
     }
     return stringBuilder.toString();
 }
     }
     return stringBuilder.toString();
 }
@@ -272,7 +272,7 @@ String EntryPointScaffolding::mangledInputPath(Vector<String>& path)
         ASSERT(structureDefinition);
         auto* next = structureDefinition->find(path[i]);
         ASSERT(next);
         ASSERT(structureDefinition);
         auto* next = structureDefinition->find(path[i]);
         ASSERT(next);
-        stringBuilder.append(makeString('.', m_typeNamer.mangledNameForStructureElement(*next)));
+        stringBuilder.flexibleAppend('.', m_typeNamer.mangledNameForStructureElement(*next));
         structureDefinition = nullptr;
         auto& unifyNode = next->type().unifyNode();
         if (is<AST::NamedType>(unifyNode)) {
         structureDefinition = nullptr;
         auto& unifyNode = next->type().unifyNode();
         if (is<AST::NamedType>(unifyNode)) {
@@ -296,7 +296,7 @@ String EntryPointScaffolding::mangledOutputPath(Vector<String>& path)
         ASSERT(structureDefinition);
         auto* next = structureDefinition->find(component);
         ASSERT(next);
         ASSERT(structureDefinition);
         auto* next = structureDefinition->find(component);
         ASSERT(next);
-        stringBuilder.append(makeString('.', m_typeNamer.mangledNameForStructureElement(*next)));
+        stringBuilder.flexibleAppend('.', m_typeNamer.mangledNameForStructureElement(*next));
         structureDefinition = nullptr;
         auto& unifyNode = next->type().unifyNode();
         if (is<AST::NamedType>(unifyNode)) {
         structureDefinition = nullptr;
         auto& unifyNode = next->type().unifyNode();
         if (is<AST::NamedType>(unifyNode)) {
@@ -313,7 +313,7 @@ String EntryPointScaffolding::unpackResourcesAndNamedBuiltIns()
 {
     StringBuilder stringBuilder;
     for (size_t i = 0; i < m_functionDefinition.parameters().size(); ++i)
 {
     StringBuilder stringBuilder;
     for (size_t i = 0; i < m_functionDefinition.parameters().size(); ++i)
-        stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*m_functionDefinition.parameters()[i]->type()), ' ', m_parameterVariables[i], ";\n"));
+        stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(*m_functionDefinition.parameters()[i]->type()), ' ', m_parameterVariables[i], ";\n");
 
     for (size_t i = 0; i < m_layout.size(); ++i) {
         auto variableName = m_namedBindGroups[i].variableName;
 
     for (size_t i = 0; i < m_layout.size(); ++i) {
         auto variableName = m_namedBindGroups[i].variableName;
@@ -330,16 +330,18 @@ String EntryPointScaffolding::unpackResourcesAndNamedBuiltIns()
                 auto& unnamedType = *m_entryPointItems.inputs[iterator->value].unnamedType;
                 auto mangledTypeName = m_typeNamer.mangledNameForType(downcast<AST::ReferenceType>(unnamedType).elementType());
 
                 auto& unnamedType = *m_entryPointItems.inputs[iterator->value].unnamedType;
                 auto mangledTypeName = m_typeNamer.mangledNameForType(downcast<AST::ReferenceType>(unnamedType).elementType());
 
-                stringBuilder.append(makeString("size_t ", lengthTemporaryName, " = ", variableName, '.', lengthElementName, ".y;\n"));
-                stringBuilder.append(makeString(lengthTemporaryName, " = ", lengthTemporaryName, " << 32;\n"));
-                stringBuilder.append(makeString(lengthTemporaryName, " = ", lengthTemporaryName, " | ", variableName, '.', lengthElementName, ".x;\n"));
-                stringBuilder.append(makeString(lengthTemporaryName, " = ", lengthTemporaryName, " / sizeof(", mangledTypeName, ");\n"));
-                stringBuilder.append(makeString("if (", lengthTemporaryName, " > 0xFFFFFFFF) ", lengthTemporaryName, " = 0xFFFFFFFF;\n"));
-                stringBuilder.append(makeString(mangledInputPath(path), " = { ", variableName, '.', elementName, ", static_cast<uint32_t>(", lengthTemporaryName, ") };\n"));
+                stringBuilder.flexibleAppend(
+                    "size_t ", lengthTemporaryName, " = ", variableName, '.', lengthElementName, ".y;\n",
+                    lengthTemporaryName, " = ", lengthTemporaryName, " << 32;\n",
+                    lengthTemporaryName, " = ", lengthTemporaryName, " | ", variableName, '.', lengthElementName, ".x;\n",
+                    lengthTemporaryName, " = ", lengthTemporaryName, " / sizeof(", mangledTypeName, ");\n",
+                    "if (", lengthTemporaryName, " > 0xFFFFFFFF) ", lengthTemporaryName, " = 0xFFFFFFFF;\n",
+                    mangledInputPath(path), " = { ", variableName, '.', elementName, ", static_cast<uint32_t>(", lengthTemporaryName, ") };\n"
+                );
             } else {
                 auto& path = m_entryPointItems.inputs[iterator->value].path;
                 auto elementName = m_namedBindGroups[i].namedBindings[j].elementName;
             } else {
                 auto& path = m_entryPointItems.inputs[iterator->value].path;
                 auto elementName = m_namedBindGroups[i].namedBindings[j].elementName;
-                stringBuilder.append(makeString(mangledInputPath(path), " = ", variableName, '.', elementName, ";\n"));
+                stringBuilder.flexibleAppend(mangledInputPath(path), " = ", variableName, '.', elementName, ";\n");
             }
         }
     }
             }
         }
     }
@@ -349,7 +351,7 @@ String EntryPointScaffolding::unpackResourcesAndNamedBuiltIns()
         auto& path = item.path;
         auto& variableName = namedBuiltIn.variableName;
         auto mangledTypeName = m_typeNamer.mangledNameForType(*item.unnamedType);
         auto& path = item.path;
         auto& variableName = namedBuiltIn.variableName;
         auto mangledTypeName = m_typeNamer.mangledNameForType(*item.unnamedType);
-        stringBuilder.append(makeString(mangledInputPath(path), " = ", mangledTypeName, '(', variableName, ");\n"));
+        stringBuilder.flexibleAppend(mangledInputPath(path), " = ", mangledTypeName, '(', variableName, ");\n");
     }
     return stringBuilder.toString();
 }
     }
     return stringBuilder.toString();
 }
@@ -387,26 +389,28 @@ String VertexEntryPointScaffolding::helperTypes()
 {
     StringBuilder stringBuilder;
 
 {
     StringBuilder stringBuilder;
 
-    stringBuilder.append(makeString("struct ", m_stageInStructName, " {\n"));
+    stringBuilder.flexibleAppend("struct ", m_stageInStructName, " {\n");
     for (auto& namedStageIn : m_namedStageIns) {
         auto mangledTypeName = m_typeNamer.mangledNameForType(*m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].unnamedType);
         auto elementName = namedStageIn.elementName;
         auto attributeIndex = namedStageIn.attributeIndex;
     for (auto& namedStageIn : m_namedStageIns) {
         auto mangledTypeName = m_typeNamer.mangledNameForType(*m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].unnamedType);
         auto elementName = namedStageIn.elementName;
         auto attributeIndex = namedStageIn.attributeIndex;
-        stringBuilder.append(makeString("    ", mangledTypeName, ' ', elementName, " [[attribute(", attributeIndex, ")]];\n"));
+        stringBuilder.flexibleAppend("    ", mangledTypeName, ' ', elementName, " [[attribute(", attributeIndex, ")]];\n");
     }
     }
-    stringBuilder.append("};\n\n");
-
-    stringBuilder.append(makeString("struct ", m_returnStructName, " {\n"));
+    stringBuilder.flexibleAppend(
+        "};\n\n"
+        "struct ", m_returnStructName, " {\n"
+    );
     for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
         auto& outputItem = m_entryPointItems.outputs[i];
         auto& internalTypeName = m_namedOutputs[i].internalTypeName;
         auto elementName = m_namedOutputs[i].elementName;
         auto attribute = attributeForSemantic(*outputItem.semantic);
     for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
         auto& outputItem = m_entryPointItems.outputs[i];
         auto& internalTypeName = m_namedOutputs[i].internalTypeName;
         auto elementName = m_namedOutputs[i].elementName;
         auto attribute = attributeForSemantic(*outputItem.semantic);
-        stringBuilder.append(makeString("    ", internalTypeName, ' ', elementName, ' ', attribute, ";\n"));
+        stringBuilder.flexibleAppend("    ", internalTypeName, ' ', elementName, ' ', attribute, ";\n");
     }
     }
-    stringBuilder.append("};\n\n");
-
-    stringBuilder.append(resourceHelperTypes());
+    stringBuilder.flexibleAppend(
+        "};\n\n",
+        resourceHelperTypes()
+    );
 
     return stringBuilder.toString();
 }
 
     return stringBuilder.toString();
 }
@@ -415,12 +419,12 @@ String VertexEntryPointScaffolding::signature(String& functionName)
 {
     StringBuilder stringBuilder;
 
 {
     StringBuilder stringBuilder;
 
-    stringBuilder.append(makeString("vertex ", m_returnStructName, ' ', functionName, '(', m_stageInStructName, ' ', m_stageInParameterName, " [[stage_in]]"));
+    stringBuilder.flexibleAppend("vertex ", m_returnStructName, ' ', functionName, '(', m_stageInStructName, ' ', m_stageInParameterName, " [[stage_in]]");
     if (auto resourceSignature = this->resourceSignature())
     if (auto resourceSignature = this->resourceSignature())
-        stringBuilder.append(makeString(", ", *resourceSignature));
+        stringBuilder.flexibleAppend(", ", *resourceSignature);
     if (auto builtInsSignature = this->builtInsSignature())
     if (auto builtInsSignature = this->builtInsSignature())
-        stringBuilder.append(makeString(", ", *builtInsSignature));
-    stringBuilder.append(")");
+        stringBuilder.flexibleAppend(", ", *builtInsSignature);
+    stringBuilder.append(')');
 
     return stringBuilder.toString();
 }
 
     return stringBuilder.toString();
 }
@@ -434,7 +438,7 @@ String VertexEntryPointScaffolding::unpack()
     for (auto& namedStageIn : m_namedStageIns) {
         auto& path = m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].path;
         auto& elementName = namedStageIn.elementName;
     for (auto& namedStageIn : m_namedStageIns) {
         auto& path = m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].path;
         auto& elementName = namedStageIn.elementName;
-        stringBuilder.append(makeString(mangledInputPath(path), " = ", m_stageInParameterName, '.', elementName, ";\n"));
+        stringBuilder.flexibleAppend(mangledInputPath(path), " = ", m_stageInParameterName, '.', elementName, ";\n");
     }
 
     return stringBuilder.toString();
     }
 
     return stringBuilder.toString();
@@ -443,17 +447,18 @@ String VertexEntryPointScaffolding::unpack()
 String VertexEntryPointScaffolding::pack(const String& inputVariableName, const String& outputVariableName)
 {
     StringBuilder stringBuilder;
 String VertexEntryPointScaffolding::pack(const String& inputVariableName, const String& outputVariableName)
 {
     StringBuilder stringBuilder;
-    stringBuilder.append(makeString(m_returnStructName, ' ', outputVariableName, ";\n"));
+
+    stringBuilder.flexibleAppend(m_returnStructName, ' ', outputVariableName, ";\n");
     if (m_entryPointItems.outputs.size() == 1 && !m_entryPointItems.outputs[0].path.size()) {
         auto& elementName = m_namedOutputs[0].elementName;
     if (m_entryPointItems.outputs.size() == 1 && !m_entryPointItems.outputs[0].path.size()) {
         auto& elementName = m_namedOutputs[0].elementName;
-        stringBuilder.append(makeString(outputVariableName, '.', elementName, " = ", inputVariableName, ";\n"));
+        stringBuilder.flexibleAppend(outputVariableName, '.', elementName, " = ", inputVariableName, ";\n");
         return stringBuilder.toString();
     }
     for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
         auto& elementName = m_namedOutputs[i].elementName;
         auto& internalTypeName = m_namedOutputs[i].internalTypeName;
         auto& path = m_entryPointItems.outputs[i].path;
         return stringBuilder.toString();
     }
     for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
         auto& elementName = m_namedOutputs[i].elementName;
         auto& internalTypeName = m_namedOutputs[i].internalTypeName;
         auto& path = m_entryPointItems.outputs[i].path;
-        stringBuilder.append(makeString(outputVariableName, '.', elementName, " = ", internalTypeName, '(', inputVariableName, mangledOutputPath(path), ");\n"));
+        stringBuilder.flexibleAppend(outputVariableName, '.', elementName, " = ", internalTypeName, '(', inputVariableName, mangledOutputPath(path), ");\n");
     }
     return stringBuilder.toString();
 }
     }
     return stringBuilder.toString();
 }
@@ -493,26 +498,28 @@ String FragmentEntryPointScaffolding::helperTypes()
 {
     StringBuilder stringBuilder;
 
 {
     StringBuilder stringBuilder;
 
-    stringBuilder.append(makeString("struct ", m_stageInStructName, " {\n"));
+    stringBuilder.flexibleAppend("struct ", m_stageInStructName, " {\n");
     for (auto& namedStageIn : m_namedStageIns) {
         auto mangledTypeName = m_typeNamer.mangledNameForType(*m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].unnamedType);
         auto elementName = namedStageIn.elementName;
         auto attributeIndex = namedStageIn.attributeIndex;
     for (auto& namedStageIn : m_namedStageIns) {
         auto mangledTypeName = m_typeNamer.mangledNameForType(*m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].unnamedType);
         auto elementName = namedStageIn.elementName;
         auto attributeIndex = namedStageIn.attributeIndex;
-        stringBuilder.append(makeString("    ", mangledTypeName, ' ', elementName, " [[user(user", attributeIndex, ")]];\n"));
+        stringBuilder.flexibleAppend("    ", mangledTypeName, ' ', elementName, " [[user(user", attributeIndex, ")]];\n");
     }
     }
-    stringBuilder.append("};\n\n");
-
-    stringBuilder.append(makeString("struct ", m_returnStructName, " {\n"));
+    stringBuilder.flexibleAppend(
+        "};\n\n"
+        "struct ", m_returnStructName, " {\n"
+    );
     for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
         auto& outputItem = m_entryPointItems.outputs[i];
         auto& internalTypeName = m_namedOutputs[i].internalTypeName;
         auto elementName = m_namedOutputs[i].elementName;
         auto attribute = attributeForSemantic(*outputItem.semantic);
     for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
         auto& outputItem = m_entryPointItems.outputs[i];
         auto& internalTypeName = m_namedOutputs[i].internalTypeName;
         auto elementName = m_namedOutputs[i].elementName;
         auto attribute = attributeForSemantic(*outputItem.semantic);
-        stringBuilder.append(makeString("    ", internalTypeName, ' ', elementName, ' ', attribute, ";\n"));
+        stringBuilder.flexibleAppend("    ", internalTypeName, ' ', elementName, ' ', attribute, ";\n");
     }
     }
-    stringBuilder.append("};\n\n");
-
-    stringBuilder.append(resourceHelperTypes());
+    stringBuilder.flexibleAppend(
+        "};\n\n",
+        resourceHelperTypes()
+    );
 
     return stringBuilder.toString();
 }
 
     return stringBuilder.toString();
 }
@@ -521,12 +528,12 @@ String FragmentEntryPointScaffolding::signature(String& functionName)
 {
     StringBuilder stringBuilder;
 
 {
     StringBuilder stringBuilder;
 
-    stringBuilder.append(makeString("fragment ", m_returnStructName, ' ', functionName, '(', m_stageInStructName, ' ', m_stageInParameterName, " [[stage_in]]"));
+    stringBuilder.flexibleAppend("fragment ", m_returnStructName, ' ', functionName, '(', m_stageInStructName, ' ', m_stageInParameterName, " [[stage_in]]");
     if (auto resourceSignature = this->resourceSignature())
     if (auto resourceSignature = this->resourceSignature())
-        stringBuilder.append(makeString(", ", *resourceSignature));
+        stringBuilder.flexibleAppend(", ", *resourceSignature);
     if (auto builtInsSignature = this->builtInsSignature())
     if (auto builtInsSignature = this->builtInsSignature())
-        stringBuilder.append(makeString(", ", *builtInsSignature));
-    stringBuilder.append(")");
+        stringBuilder.flexibleAppend(", ", *builtInsSignature);
+    stringBuilder.append(')');
 
     return stringBuilder.toString();
 }
 
     return stringBuilder.toString();
 }
@@ -540,7 +547,7 @@ String FragmentEntryPointScaffolding::unpack()
     for (auto& namedStageIn : m_namedStageIns) {
         auto& path = m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].path;
         auto& elementName = namedStageIn.elementName;
     for (auto& namedStageIn : m_namedStageIns) {
         auto& path = m_entryPointItems.inputs[namedStageIn.indexInEntryPointItems].path;
         auto& elementName = namedStageIn.elementName;
-        stringBuilder.append(makeString(mangledInputPath(path), " = ", m_stageInParameterName, '.', elementName, ";\n"));
+        stringBuilder.flexibleAppend(mangledInputPath(path), " = ", m_stageInParameterName, '.', elementName, ";\n");
     }
 
     return stringBuilder.toString();
     }
 
     return stringBuilder.toString();
@@ -549,17 +556,18 @@ String FragmentEntryPointScaffolding::unpack()
 String FragmentEntryPointScaffolding::pack(const String& inputVariableName, const String& outputVariableName)
 {
     StringBuilder stringBuilder;
 String FragmentEntryPointScaffolding::pack(const String& inputVariableName, const String& outputVariableName)
 {
     StringBuilder stringBuilder;
-    stringBuilder.append(makeString(m_returnStructName, ' ', outputVariableName, ";\n"));
+
+    stringBuilder.flexibleAppend(m_returnStructName, ' ', outputVariableName, ";\n");
     if (m_entryPointItems.outputs.size() == 1 && !m_entryPointItems.outputs[0].path.size()) {
         auto& elementName = m_namedOutputs[0].elementName;
     if (m_entryPointItems.outputs.size() == 1 && !m_entryPointItems.outputs[0].path.size()) {
         auto& elementName = m_namedOutputs[0].elementName;
-        stringBuilder.append(makeString(outputVariableName, '.', elementName, " = ", inputVariableName, ";\n"));
+        stringBuilder.flexibleAppend(outputVariableName, '.', elementName, " = ", inputVariableName, ";\n");
         return stringBuilder.toString();
     }
     for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
         auto& elementName = m_namedOutputs[i].elementName;
         auto& internalTypeName = m_namedOutputs[i].internalTypeName;
         auto& path = m_entryPointItems.outputs[i].path;
         return stringBuilder.toString();
     }
     for (size_t i = 0; i < m_entryPointItems.outputs.size(); ++i) {
         auto& elementName = m_namedOutputs[i].elementName;
         auto& internalTypeName = m_namedOutputs[i].internalTypeName;
         auto& path = m_entryPointItems.outputs[i].path;
-        stringBuilder.append(makeString(outputVariableName, '.', elementName, " = ", internalTypeName, '(', inputVariableName, mangledOutputPath(path), ");\n"));
+        stringBuilder.flexibleAppend(outputVariableName, '.', elementName, " = ", internalTypeName, '(', inputVariableName, mangledOutputPath(path), ");\n");
     }
     return stringBuilder.toString();
 }
     }
     return stringBuilder.toString();
 }
@@ -578,18 +586,18 @@ String ComputeEntryPointScaffolding::signature(String& functionName)
 {
     StringBuilder stringBuilder;
 
 {
     StringBuilder stringBuilder;
 
-    stringBuilder.append(makeString("kernel void ", functionName, '('));
+    stringBuilder.flexibleAppend("kernel void ", functionName, '(');
     bool empty = true;
     if (auto resourceSignature = this->resourceSignature()) {
         empty = false;
     bool empty = true;
     if (auto resourceSignature = this->resourceSignature()) {
         empty = false;
-        stringBuilder.append(makeString(*resourceSignature));
+        stringBuilder.append(*resourceSignature);
     }
     if (auto builtInsSignature = this->builtInsSignature()) {
         if (!empty)
             stringBuilder.append(", ");
         stringBuilder.append(*builtInsSignature);
     }
     }
     if (auto builtInsSignature = this->builtInsSignature()) {
         if (!empty)
             stringBuilder.append(", ");
         stringBuilder.append(*builtInsSignature);
     }
-    stringBuilder.append(")");
+    stringBuilder.append(')');
 
     return stringBuilder.toString();
 }
 
     return stringBuilder.toString();
 }
index 93f2bcd..e79f257 100644 (file)
@@ -74,7 +74,7 @@ void FunctionDeclarationWriter::visit(AST::FunctionDeclaration& functionDeclarat
 
     auto iterator = m_functionMapping.find(&functionDeclaration);
     ASSERT(iterator != m_functionMapping.end());
 
     auto iterator = m_functionMapping.find(&functionDeclaration);
     ASSERT(iterator != m_functionMapping.end());
-    m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(functionDeclaration.type()), ' ', iterator->value, '('));
+    m_stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(functionDeclaration.type()), ' ', iterator->value, '(');
     for (size_t i = 0; i < functionDeclaration.parameters().size(); ++i) {
         if (i)
             m_stringBuilder.append(", ");
     for (size_t i = 0; i < functionDeclaration.parameters().size(); ++i) {
         if (i)
             m_stringBuilder.append(", ");
@@ -91,14 +91,14 @@ public:
         , m_functionMapping(functionMapping)
         , m_layout(layout)
     {
         , m_functionMapping(functionMapping)
         , m_layout(layout)
     {
-        m_stringBuilder.append(makeString(
+        m_stringBuilder.flexibleAppend(
             "template <typename T>\n"
             "inline void ", memsetZeroFunctionName, "(thread T& value)\n"
             "{\n"
             "    thread char* ptr = static_cast<thread char*>(static_cast<thread void*>(&value));\n"
             "    for (size_t i = 0; i < sizeof(T); ++i)\n"
             "        ptr[i] = 0;\n"
             "template <typename T>\n"
             "inline void ", memsetZeroFunctionName, "(thread T& value)\n"
             "{\n"
             "    thread char* ptr = static_cast<thread char*>(static_cast<thread void*>(&value));\n"
             "    for (size_t i = 0; i < sizeof(T); ++i)\n"
             "        ptr[i] = 0;\n"
-            "}\n"));
+            "}\n");
     }
 
     static constexpr const char* memsetZeroFunctionName = "memsetZero";
     }
 
     static constexpr const char* memsetZeroFunctionName = "memsetZero";
@@ -229,10 +229,11 @@ void FunctionDefinitionWriter::visit(AST::FunctionDefinition& functionDefinition
         if (!entryPointScaffolding)
             return;
         m_entryPointScaffolding = WTFMove(entryPointScaffolding);
         if (!entryPointScaffolding)
             return;
         m_entryPointScaffolding = WTFMove(entryPointScaffolding);
-        m_stringBuilder.append(m_entryPointScaffolding->helperTypes());
-        m_stringBuilder.append('\n');
-        m_stringBuilder.append(makeString(m_entryPointScaffolding->signature(iterator->value), " {\n"));
-        m_stringBuilder.append(m_entryPointScaffolding->unpack());
+        m_stringBuilder.flexibleAppend(
+            m_entryPointScaffolding->helperTypes(), '\n',
+            m_entryPointScaffolding->signature(iterator->value), " {\n",
+            m_entryPointScaffolding->unpack()
+        );
         for (size_t i = 0; i < functionDefinition.parameters().size(); ++i) {
             auto addResult = m_variableMapping.add(&functionDefinition.parameters()[i], m_entryPointScaffolding->parameterVariables()[i]);
             ASSERT_UNUSED(addResult, addResult.isNewEntry);
         for (size_t i = 0; i < functionDefinition.parameters().size(); ++i) {
             auto addResult = m_variableMapping.add(&functionDefinition.parameters()[i], m_entryPointScaffolding->parameterVariables()[i]);
             ASSERT_UNUSED(addResult, addResult.isNewEntry);
@@ -243,7 +244,7 @@ void FunctionDefinitionWriter::visit(AST::FunctionDefinition& functionDefinition
         m_entryPointScaffolding = nullptr;
     } else {
         ASSERT(m_entryPointScaffolding == nullptr);
         m_entryPointScaffolding = nullptr;
     } else {
         ASSERT(m_entryPointScaffolding == nullptr);
-        m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(functionDefinition.type()), ' ', iterator->value, '('));
+        m_stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(functionDefinition.type()), ' ', iterator->value, '(');
         for (size_t i = 0; i < functionDefinition.parameters().size(); ++i) {
             auto& parameter = functionDefinition.parameters()[i];
             if (i)
         for (size_t i = 0; i < functionDefinition.parameters().size(); ++i) {
             auto& parameter = functionDefinition.parameters()[i];
             if (i)
@@ -251,7 +252,7 @@ void FunctionDefinitionWriter::visit(AST::FunctionDefinition& functionDefinition
             auto parameterName = generateNextVariableName();
             auto addResult = m_variableMapping.add(&parameter, parameterName);
             ASSERT_UNUSED(addResult, addResult.isNewEntry);
             auto parameterName = generateNextVariableName();
             auto addResult = m_variableMapping.add(&parameter, parameterName);
             ASSERT_UNUSED(addResult, addResult.isNewEntry);
-            m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*parameter->type()), ' ', parameterName));
+            m_stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(*parameter->type()), ' ', parameterName);
         }
         m_stringBuilder.append(") {\n");
         checkErrorAndVisit(functionDefinition.block());
         }
         m_stringBuilder.append(") {\n");
         checkErrorAndVisit(functionDefinition.block());
@@ -287,8 +288,10 @@ void FunctionDefinitionWriter::visit(AST::Break&)
         break;
     case BreakContext::Loop:
         ASSERT(m_breakOutOfCurrentLoopEarlyVariable.length());
         break;
     case BreakContext::Loop:
         ASSERT(m_breakOutOfCurrentLoopEarlyVariable.length());
-        m_stringBuilder.append(makeString(m_breakOutOfCurrentLoopEarlyVariable, " = true;\n"));
-        m_stringBuilder.append("break;\n");
+        m_stringBuilder.flexibleAppend(
+            m_breakOutOfCurrentLoopEarlyVariable, " = true;\n"
+            "break;\n"
+        );
         break;
     }
 }
         break;
     }
 }
@@ -314,20 +317,23 @@ void FunctionDefinitionWriter::emitLoop(LoopConditionLocation loopConditionLocat
 {
     SetForScope<String> loopVariableScope(m_breakOutOfCurrentLoopEarlyVariable, generateNextVariableName());
 
 {
     SetForScope<String> loopVariableScope(m_breakOutOfCurrentLoopEarlyVariable, generateNextVariableName());
 
-    m_stringBuilder.append(makeString("bool ", m_breakOutOfCurrentLoopEarlyVariable, " = false;\n"));
-
-    m_stringBuilder.append("while (true) {\n");
+    m_stringBuilder.flexibleAppend(
+        "bool ", m_breakOutOfCurrentLoopEarlyVariable, " = false;\n",
+        "while (true) {\n"
+    );
 
     if (loopConditionLocation == LoopConditionLocation::BeforeBody && conditionExpression) {
         checkErrorAndVisit(*conditionExpression);
 
     if (loopConditionLocation == LoopConditionLocation::BeforeBody && conditionExpression) {
         checkErrorAndVisit(*conditionExpression);
-        m_stringBuilder.append(makeString("if (!", takeLastValue(), ") break;\n"));
+        m_stringBuilder.flexibleAppend("if (!", takeLastValue(), ") break;\n");
     }
 
     m_stringBuilder.append("do {\n");
     SetForScope<Optional<BreakContext>> breakContext(m_currentBreakContext, BreakContext::Loop);
     checkErrorAndVisit(body);
     }
 
     m_stringBuilder.append("do {\n");
     SetForScope<Optional<BreakContext>> breakContext(m_currentBreakContext, BreakContext::Loop);
     checkErrorAndVisit(body);
-    m_stringBuilder.append("} while(false); \n");
-    m_stringBuilder.append(makeString("if (", m_breakOutOfCurrentLoopEarlyVariable, ") break;\n"));
+    m_stringBuilder.flexibleAppend(
+        "} while(false); \n"
+        "if (", m_breakOutOfCurrentLoopEarlyVariable, ") break;\n"
+    );
 
     if (increment) {
         checkErrorAndVisit(*increment);
 
     if (increment) {
         checkErrorAndVisit(*increment);
@@ -338,7 +344,7 @@ void FunctionDefinitionWriter::emitLoop(LoopConditionLocation loopConditionLocat
 
     if (loopConditionLocation == LoopConditionLocation::AfterBody && conditionExpression) {
         checkErrorAndVisit(*conditionExpression);
 
     if (loopConditionLocation == LoopConditionLocation::AfterBody && conditionExpression) {
         checkErrorAndVisit(*conditionExpression);
-        m_stringBuilder.append(makeString("if (!", takeLastValue(), ") break;\n"));
+        m_stringBuilder.flexibleAppend("if (!", takeLastValue(), ") break;\n");
     }
 
     m_stringBuilder.append("} \n");
     }
 
     m_stringBuilder.append("} \n");
@@ -372,7 +378,7 @@ void FunctionDefinitionWriter::visit(AST::ForLoop& forLoop)
 void FunctionDefinitionWriter::visit(AST::IfStatement& ifStatement)
 {
     checkErrorAndVisit(ifStatement.conditional());
 void FunctionDefinitionWriter::visit(AST::IfStatement& ifStatement)
 {
     checkErrorAndVisit(ifStatement.conditional());
-    m_stringBuilder.append(makeString("if (", takeLastValue(), ") {\n"));
+    m_stringBuilder.flexibleAppend("if (", takeLastValue(), ") {\n");
     checkErrorAndVisit(ifStatement.body());
     if (ifStatement.elseBody()) {
         m_stringBuilder.append("} else {\n");
     checkErrorAndVisit(ifStatement.body());
     if (ifStatement.elseBody()) {
         m_stringBuilder.append("} else {\n");
@@ -387,10 +393,12 @@ void FunctionDefinitionWriter::visit(AST::Return& returnStatement)
         checkErrorAndVisit(*returnStatement.value());
         if (m_entryPointScaffolding) {
             auto variableName = generateNextVariableName();
         checkErrorAndVisit(*returnStatement.value());
         if (m_entryPointScaffolding) {
             auto variableName = generateNextVariableName();
-            m_stringBuilder.append(m_entryPointScaffolding->pack(takeLastValue(), variableName));
-            m_stringBuilder.append(makeString("return ", variableName, ";\n"));
+            m_stringBuilder.flexibleAppend(
+                m_entryPointScaffolding->pack(takeLastValue(), variableName),
+                "return ", variableName, ";\n"
+            );
         } else
         } else
-            m_stringBuilder.append(makeString("return ", takeLastValue(), ";\n"));
+            m_stringBuilder.flexibleAppend("return ", takeLastValue(), ";\n");
     } else
         m_stringBuilder.append("return;\n");
 }
     } else
         m_stringBuilder.append("return;\n");
 }
@@ -399,7 +407,7 @@ void FunctionDefinitionWriter::visit(AST::SwitchStatement& switchStatement)
 {
     checkErrorAndVisit(switchStatement.value());
 
 {
     checkErrorAndVisit(switchStatement.value());
 
-    m_stringBuilder.append(makeString("switch (", takeLastValue(), ") {"));
+    m_stringBuilder.flexibleAppend("switch (", takeLastValue(), ") {");
     for (auto& switchCase : switchStatement.switchCases())
         checkErrorAndVisit(switchCase);
     m_stringBuilder.append("}\n");
     for (auto& switchCase : switchStatement.switchCases())
         checkErrorAndVisit(switchCase);
     m_stringBuilder.append("}\n");
@@ -408,7 +416,7 @@ void FunctionDefinitionWriter::visit(AST::SwitchStatement& switchStatement)
 void FunctionDefinitionWriter::visit(AST::SwitchCase& switchCase)
 {
     if (switchCase.value())
 void FunctionDefinitionWriter::visit(AST::SwitchCase& switchCase)
 {
     if (switchCase.value())
-        m_stringBuilder.append(makeString("case ", constantExpressionString(*switchCase.value()), ":\n"));
+        m_stringBuilder.flexibleAppend("case ", constantExpressionString(*switchCase.value()), ":\n");
     else
         m_stringBuilder.append("default:\n");
     SetForScope<Optional<BreakContext>> breakContext(m_currentBreakContext, BreakContext::Switch);
     else
         m_stringBuilder.append("default:\n");
     SetForScope<Optional<BreakContext>> breakContext(m_currentBreakContext, BreakContext::Switch);
@@ -425,7 +433,7 @@ void FunctionDefinitionWriter::visit(AST::IntegerLiteral& integerLiteral)
 {
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(integerLiteral.resolvedType());
 {
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(integerLiteral.resolvedType());
-    m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", integerLiteral.value(), ");\n"));
+    m_stringBuilder.flexibleAppend(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", integerLiteral.value(), ");\n");
     appendRightValue(integerLiteral, variableName);
 }
 
     appendRightValue(integerLiteral, variableName);
 }
 
@@ -433,7 +441,7 @@ void FunctionDefinitionWriter::visit(AST::UnsignedIntegerLiteral& unsignedIntege
 {
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(unsignedIntegerLiteral.resolvedType());
 {
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(unsignedIntegerLiteral.resolvedType());
-    m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", unsignedIntegerLiteral.value(), ");\n"));
+    m_stringBuilder.flexibleAppend(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", unsignedIntegerLiteral.value(), ");\n");
     appendRightValue(unsignedIntegerLiteral, variableName);
 }
 
     appendRightValue(unsignedIntegerLiteral, variableName);
 }
 
@@ -441,7 +449,7 @@ void FunctionDefinitionWriter::visit(AST::FloatLiteral& floatLiteral)
 {
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(floatLiteral.resolvedType());
 {
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(floatLiteral.resolvedType());
-    m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", floatLiteral.value(), ");\n"));
+    m_stringBuilder.flexibleAppend(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", floatLiteral.value(), ");\n");
     appendRightValue(floatLiteral, variableName);
 }
 
     appendRightValue(floatLiteral, variableName);
 }
 
@@ -452,12 +460,11 @@ void FunctionDefinitionWriter::visit(AST::NullLiteral& nullLiteral)
     bool isArrayReferenceType = is<AST::ArrayReferenceType>(unnamedType);
 
     auto variableName = generateNextVariableName();
     bool isArrayReferenceType = is<AST::ArrayReferenceType>(unnamedType);
 
     auto variableName = generateNextVariableName();
-    m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(nullLiteral.resolvedType()), ' ', variableName, " = "));
+    m_stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(nullLiteral.resolvedType()), ' ', variableName, " = ");
     if (isArrayReferenceType)
     if (isArrayReferenceType)
-        m_stringBuilder.append("{ nullptr, 0 }");
+        m_stringBuilder.append("{ nullptr, 0 };\n");
     else
     else
-        m_stringBuilder.append("nullptr");
-    m_stringBuilder.append(";\n");
+        m_stringBuilder.append("nullptr;\n");
     appendRightValue(nullLiteral, variableName);
 }
 
     appendRightValue(nullLiteral, variableName);
 }
 
@@ -465,7 +472,7 @@ void FunctionDefinitionWriter::visit(AST::BooleanLiteral& booleanLiteral)
 {
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(booleanLiteral.resolvedType());
 {
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(booleanLiteral.resolvedType());
-    m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", booleanLiteral.value() ? "true" : "false", ");\n"));
+    m_stringBuilder.flexibleAppend(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", booleanLiteral.value() ? "true" : "false", ");\n");
     appendRightValue(booleanLiteral, variableName);
 }
 
     appendRightValue(booleanLiteral, variableName);
 }
 
@@ -475,7 +482,7 @@ void FunctionDefinitionWriter::visit(AST::EnumerationMemberLiteral& enumerationM
     ASSERT(enumerationMemberLiteral.enumerationDefinition());
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(enumerationMemberLiteral.resolvedType());
     ASSERT(enumerationMemberLiteral.enumerationDefinition());
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(enumerationMemberLiteral.resolvedType());
-    m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = ", mangledTypeName, "::", m_typeNamer.mangledNameForEnumerationMember(*enumerationMemberLiteral.enumerationMember()), ";\n"));
+    m_stringBuilder.flexibleAppend(mangledTypeName, ' ', variableName, " = ", mangledTypeName, "::", m_typeNamer.mangledNameForEnumerationMember(*enumerationMemberLiteral.enumerationMember()), ";\n");
     appendRightValue(enumerationMemberLiteral, variableName);
 }
 
     appendRightValue(enumerationMemberLiteral, variableName);
 }
 
@@ -498,8 +505,10 @@ void FunctionDefinitionWriter::visit(AST::GlobalVariableReference& globalVariabl
     auto pointerName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(globalVariableReference.resolvedType());
     checkErrorAndVisit(globalVariableReference.base());
     auto pointerName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(globalVariableReference.resolvedType());
     checkErrorAndVisit(globalVariableReference.base());
-    m_stringBuilder.append(makeString("thread ", mangledTypeName, "* ", pointerName, " = &", takeLastValue(), "->", m_typeNamer.mangledNameForStructureElement(globalVariableReference.structField()), ";\n"));
-    m_stringBuilder.append(makeString(mangledTypeName, ' ', valueName, " = ", "*", pointerName, ";\n"));
+    m_stringBuilder.flexibleAppend(
+        "thread ", mangledTypeName, "* ", pointerName, " = &", takeLastValue(), "->", m_typeNamer.mangledNameForStructureElement(globalVariableReference.structField()), ";\n",
+        mangledTypeName, ' ', valueName, " = ", "*", pointerName, ";\n"
+    );
     appendLeftValue(globalVariableReference, valueName, pointerName);
 }
 
     appendLeftValue(globalVariableReference, valueName, pointerName);
 }
 
@@ -528,9 +537,9 @@ void FunctionDefinitionWriter::visit(AST::VariableDeclaration& variableDeclarati
     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198160 Implement qualifiers.
     if (variableDeclaration.initializer()) {
         checkErrorAndVisit(*variableDeclaration.initializer());
     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198160 Implement qualifiers.
     if (variableDeclaration.initializer()) {
         checkErrorAndVisit(*variableDeclaration.initializer());
-        m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, " = ", takeLastValue(), ";\n"));
+        m_stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, " = ", takeLastValue(), ";\n");
     } else
     } else
-        m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, ";\n"));
+        m_stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, ";\n");
 }
 
 void FunctionDefinitionWriter::visit(AST::AssignmentExpression& assignmentExpression)
 }
 
 void FunctionDefinitionWriter::visit(AST::AssignmentExpression& assignmentExpression)
@@ -539,7 +548,7 @@ void FunctionDefinitionWriter::visit(AST::AssignmentExpression& assignmentExpres
     auto pointerName = takeLastLeftValue();
     checkErrorAndVisit(assignmentExpression.right());
     auto rightName = takeLastValue();
     auto pointerName = takeLastLeftValue();
     checkErrorAndVisit(assignmentExpression.right());
     auto rightName = takeLastValue();
-    m_stringBuilder.append(makeString("if (", pointerName, ") *", pointerName, " = ", rightName, ";\n"));
+    m_stringBuilder.flexibleAppend("if (", pointerName, ") *", pointerName, " = ", rightName, ";\n");
     appendRightValue(assignmentExpression, rightName);
 }
 
     appendRightValue(assignmentExpression, rightName);
 }
 
@@ -554,8 +563,8 @@ void FunctionDefinitionWriter::visit(AST::CallExpression& callExpression)
     ASSERT(iterator != m_functionMapping.end());
     auto variableName = generateNextVariableName();
     if (!matches(callExpression.resolvedType(), m_intrinsics.voidType()))
     ASSERT(iterator != m_functionMapping.end());
     auto variableName = generateNextVariableName();
     if (!matches(callExpression.resolvedType(), m_intrinsics.voidType()))
-        m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(callExpression.resolvedType()), ' ', variableName, " = "));
-    m_stringBuilder.append(makeString(iterator->value, '('));
+        m_stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(callExpression.resolvedType()), ' ', variableName, " = ");
+    m_stringBuilder.flexibleAppend(iterator->value, '(');
     for (size_t i = 0; i < argumentNames.size(); ++i) {
         if (i)
             m_stringBuilder.append(", ");
     for (size_t i = 0; i < argumentNames.size(); ++i) {
         if (i)
             m_stringBuilder.append(", ");
@@ -581,10 +590,12 @@ void FunctionDefinitionWriter::visit(AST::DereferenceExpression& dereferenceExpr
     auto right = takeLastValue();
     auto variableName = generateNextVariableName();
     auto pointerName = generateNextVariableName();
     auto right = takeLastValue();
     auto variableName = generateNextVariableName();
     auto pointerName = generateNextVariableName();
-    m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(dereferenceExpression.pointer().resolvedType()), ' ', pointerName, " = ", right, ";\n"));
-    m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(dereferenceExpression.resolvedType()), ' ', variableName, ";\n"));
-    m_stringBuilder.append(makeString("if (", pointerName, ") ", variableName, " = *", right, ";\n"));
-    m_stringBuilder.append(makeString("else ", memsetZeroFunctionName, '(', variableName, ");\n"));
+    m_stringBuilder.flexibleAppend(
+        m_typeNamer.mangledNameForType(dereferenceExpression.pointer().resolvedType()), ' ', pointerName, " = ", right, ";\n",
+        m_typeNamer.mangledNameForType(dereferenceExpression.resolvedType()), ' ', variableName, ";\n",
+        "if (", pointerName, ") ", variableName, " = *", right, ";\n",
+        "else ", memsetZeroFunctionName, '(', variableName, ");\n"
+    );
     appendLeftValue(dereferenceExpression, variableName, pointerName);
 }
 
     appendLeftValue(dereferenceExpression, variableName, pointerName);
 }
 
@@ -595,7 +606,7 @@ void FunctionDefinitionWriter::visit(AST::LogicalExpression& logicalExpression)
     checkErrorAndVisit(logicalExpression.right());
     auto right = takeLastValue();
     auto variableName = generateNextVariableName();
     checkErrorAndVisit(logicalExpression.right());
     auto right = takeLastValue();
     auto variableName = generateNextVariableName();
-    m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(logicalExpression.resolvedType()), ' ', variableName, " = ", left));
+    m_stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(logicalExpression.resolvedType()), ' ', variableName, " = ", left);
     switch (logicalExpression.type()) {
     case AST::LogicalExpression::Type::And:
         m_stringBuilder.append(" && ");
     switch (logicalExpression.type()) {
     case AST::LogicalExpression::Type::And:
         m_stringBuilder.append(" && ");
@@ -605,7 +616,7 @@ void FunctionDefinitionWriter::visit(AST::LogicalExpression& logicalExpression)
         m_stringBuilder.append(" || ");
         break;
     }
         m_stringBuilder.append(" || ");
         break;
     }
-    m_stringBuilder.append(makeString(right, ";\n"));
+    m_stringBuilder.flexibleAppend(right, ";\n");
     appendRightValue(logicalExpression, variableName);
 }
 
     appendRightValue(logicalExpression, variableName);
 }
 
@@ -614,7 +625,7 @@ void FunctionDefinitionWriter::visit(AST::LogicalNotExpression& logicalNotExpres
     checkErrorAndVisit(logicalNotExpression.operand());
     auto operand = takeLastValue();
     auto variableName = generateNextVariableName();
     checkErrorAndVisit(logicalNotExpression.operand());
     auto operand = takeLastValue();
     auto variableName = generateNextVariableName();
-    m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(logicalNotExpression.resolvedType()), ' ', variableName, " = !", operand, ";\n"));
+    m_stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(logicalNotExpression.resolvedType()), ' ', variableName, " = !", operand, ";\n");
     appendRightValue(logicalNotExpression, variableName);
 }
 
     appendRightValue(logicalNotExpression, variableName);
 }
 
@@ -628,16 +639,18 @@ void FunctionDefinitionWriter::visit(AST::MakeArrayReferenceExpression& makeArra
     auto mangledTypeName = m_typeNamer.mangledNameForType(makeArrayReferenceExpression.resolvedType());
     if (is<AST::PointerType>(makeArrayReferenceExpression.leftValue().resolvedType())) {
         auto ptrValue = takeLastValue();
     auto mangledTypeName = m_typeNamer.mangledNameForType(makeArrayReferenceExpression.resolvedType());
     if (is<AST::PointerType>(makeArrayReferenceExpression.leftValue().resolvedType())) {
         auto ptrValue = takeLastValue();
-        m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, ";\n"));
-        m_stringBuilder.append(makeString("if (", ptrValue, ") ", variableName, " = { ", ptrValue, ", 1};\n"));
-        m_stringBuilder.append(makeString("else ", variableName, " = { nullptr, 0 };\n"));
+        m_stringBuilder.flexibleAppend(
+            mangledTypeName, ' ', variableName, ";\n",
+            "if (", ptrValue, ") ", variableName, " = { ", ptrValue, ", 1};\n",
+            "else ", variableName, " = { nullptr, 0 };\n"
+        );
     } else if (is<AST::ArrayType>(makeArrayReferenceExpression.leftValue().resolvedType())) {
         auto lValue = takeLastLeftValue();
         auto& arrayType = downcast<AST::ArrayType>(makeArrayReferenceExpression.leftValue().resolvedType());
     } else if (is<AST::ArrayType>(makeArrayReferenceExpression.leftValue().resolvedType())) {
         auto lValue = takeLastLeftValue();
         auto& arrayType = downcast<AST::ArrayType>(makeArrayReferenceExpression.leftValue().resolvedType());
-        m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { ", lValue, "->data(), ", arrayType.numElements(), " };\n"));
+        m_stringBuilder.flexibleAppend(mangledTypeName, ' ', variableName, " = { ", lValue, "->data(), ", arrayType.numElements(), " };\n");
     } else {
         auto lValue = takeLastLeftValue();
     } else {
         auto lValue = takeLastLeftValue();
-        m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { ", lValue, ", 1 };\n"));
+        m_stringBuilder.flexibleAppend(mangledTypeName, ' ', variableName, " = { ", lValue, ", 1 };\n");
     }
     appendRightValue(makeArrayReferenceExpression, variableName);
 }
     }
     appendRightValue(makeArrayReferenceExpression, variableName);
 }
@@ -647,7 +660,7 @@ void FunctionDefinitionWriter::visit(AST::MakePointerExpression& makePointerExpr
     checkErrorAndVisit(makePointerExpression.leftValue());
     auto pointer = takeLastLeftValue();
     auto variableName = generateNextVariableName();
     checkErrorAndVisit(makePointerExpression.leftValue());
     auto pointer = takeLastLeftValue();
     auto variableName = generateNextVariableName();
-    m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(makePointerExpression.resolvedType()), ' ', variableName, " = ", pointer, ";\n"));
+    m_stringBuilder.flexibleAppend(m_typeNamer.mangledNameForType(makePointerExpression.resolvedType()), ' ', variableName, " = ", pointer, ";\n");
     appendRightValue(makePointerExpression, variableName);
 }
 
     appendRightValue(makePointerExpression, variableName);
 }
 
@@ -663,15 +676,20 @@ void FunctionDefinitionWriter::visit(AST::TernaryExpression& ternaryExpression)
     auto check = takeLastValue();
 
     auto variableName = generateNextVariableName();
     auto check = takeLastValue();
 
     auto variableName = generateNextVariableName();
-    m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(ternaryExpression.resolvedType()), ' ', variableName, ";\n"));
-
-    m_stringBuilder.append(makeString("if (", check, ") {\n"));
+    m_stringBuilder.flexibleAppend(
+        m_typeNamer.mangledNameForType(ternaryExpression.resolvedType()), ' ', variableName, ";\n"
+        "if (", check, ") {\n"
+    );
     checkErrorAndVisit(ternaryExpression.bodyExpression());
     checkErrorAndVisit(ternaryExpression.bodyExpression());
-    m_stringBuilder.append(makeString(variableName, " = ", takeLastValue(), ";\n"));
-    m_stringBuilder.append("} else {\n");
+    m_stringBuilder.flexibleAppend(
+        variableName, " = ", takeLastValue(), ";\n"
+        "} else {\n"
+    );
     checkErrorAndVisit(ternaryExpression.elseExpression());
     checkErrorAndVisit(ternaryExpression.elseExpression());
-    m_stringBuilder.append(makeString(variableName, " = ", takeLastValue(), ";\n"));
-    m_stringBuilder.append("}\n");
+    m_stringBuilder.flexibleAppend(
+        variableName, " = ", takeLastValue(), ";\n"
+        "}\n"
+    );
     appendRightValue(ternaryExpression, variableName);
 }
 
     appendRightValue(ternaryExpression, variableName);
 }
 
@@ -681,7 +699,7 @@ void FunctionDefinitionWriter::visit(AST::VariableReference& variableReference)
     auto iterator = m_variableMapping.find(variableReference.variable());
     ASSERT(iterator != m_variableMapping.end());
     auto pointerName = generateNextVariableName();
     auto iterator = m_variableMapping.find(variableReference.variable());
     ASSERT(iterator != m_variableMapping.end());
     auto pointerName = generateNextVariableName();
-    m_stringBuilder.append(makeString("thread ", m_typeNamer.mangledNameForType(variableReference.resolvedType()), "* ", pointerName, " = &", iterator->value, ";\n"));
+    m_stringBuilder.flexibleAppend("thread ", m_typeNamer.mangledNameForType(variableReference.resolvedType()), "* ", pointerName, " = &", iterator->value, ";\n");
     appendLeftValue(variableReference, iterator->value, pointerName);
 }
 
     appendLeftValue(variableReference, iterator->value, pointerName);
 }
 
index b2dd84e..88cb31b 100644 (file)
@@ -43,26 +43,27 @@ static constexpr bool dumpMetalCode = false;
 
 static String generateMetalCodeShared(String&& metalTypes, String&& metalFunctions)
 {
 
 static String generateMetalCodeShared(String&& metalTypes, String&& metalFunctions)
 {
-    StringBuilder stringBuilder;
-    stringBuilder.append("#include <metal_stdlib>\n");
-    stringBuilder.append("#include <metal_atomic>\n");
-    stringBuilder.append("#include <metal_math>\n");
-    stringBuilder.append("#include <metal_relational>\n");
-    stringBuilder.append("#include <metal_compute>\n");
-    stringBuilder.append("#include <metal_texture>\n");
-    stringBuilder.append("\n");
-    stringBuilder.append("using namespace metal;\n");
-    stringBuilder.append("\n");
-
-    stringBuilder.append(WTFMove(metalTypes));
-    stringBuilder.append(WTFMove(metalFunctions));
+    auto generatedMetalCode = makeString(
+        "#include <metal_stdlib>\n"
+        "#include <metal_atomic>\n"
+        "#include <metal_math>\n"
+        "#include <metal_relational>\n"
+        "#include <metal_compute>\n"
+        "#include <metal_texture>\n"
+        "\n"
+        "using namespace metal;\n"
+        "\n",
+
+        WTFMove(metalTypes),
+        WTFMove(metalFunctions)
+    );
 
     if (dumpMetalCode) {
         dataLogLn("Generated Metal code: ");
 
     if (dumpMetalCode) {
         dataLogLn("Generated Metal code: ");
-        dataLogLn(stringBuilder.toString());
+        dataLogLn(generatedMetalCode);
     }
 
     }
 
-    return stringBuilder.toString();
+    return generatedMetalCode;
 }
 
 RenderMetalCode generateMetalCode(Program& program, MatchedRenderSemantics&& matchedSemantics, Layout& layout)
 }
 
 RenderMetalCode generateMetalCode(Program& program, MatchedRenderSemantics&& matchedSemantics, Layout& layout)
index 83ab25a..818958e 100644 (file)
@@ -127,18 +127,20 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         auto& returnType = nativeFunctionDeclaration.type();
         auto metalReturnName = typeNamer.mangledNameForType(returnType);
         if (!nativeFunctionDeclaration.parameters().size()) {
         auto& returnType = nativeFunctionDeclaration.type();
         auto metalReturnName = typeNamer.mangledNameForType(returnType);
         if (!nativeFunctionDeclaration.parameters().size()) {
-            stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, "() {\n"));
-            stringBuilder.append(makeString("    ", metalReturnName, " x;\n"));
-            stringBuilder.append(makeString("    ", memsetZeroFunctionName, "(x);\n"));
-            stringBuilder.append("    return x;\n");
-            stringBuilder.append("}\n");
+            stringBuilder.flexibleAppend(
+                metalReturnName, ' ', outputFunctionName, "() {\n"
+                "    ", metalReturnName, " x;\n"
+                "    ", memsetZeroFunctionName, "(x);\n"
+                "    return x;\n"
+                "}\n"
+            );
             return stringBuilder.toString();
         }
 
         ASSERT(nativeFunctionDeclaration.parameters().size() == 1);
         auto& parameterType = *nativeFunctionDeclaration.parameters()[0]->type();
         auto metalParameterName = typeNamer.mangledNameForType(parameterType);
             return stringBuilder.toString();
         }
 
         ASSERT(nativeFunctionDeclaration.parameters().size() == 1);
         auto& parameterType = *nativeFunctionDeclaration.parameters()[0]->type();
         auto metalParameterName = typeNamer.mangledNameForType(parameterType);
-        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " x) {\n"));
+        stringBuilder.flexibleAppend(metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " x) {\n");
 
         {
             auto isEnumerationDefinition = [] (auto& type) {
 
         {
             auto isEnumerationDefinition = [] (auto& type) {
@@ -151,15 +153,17 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
                 bool hasZeroCase = false;
                 for (auto& member : enumerationDefinition.enumerationMembers()) {
                     hasZeroCase |= !member.get().value();
                 bool hasZeroCase = false;
                 for (auto& member : enumerationDefinition.enumerationMembers()) {
                     hasZeroCase |= !member.get().value();
-                    stringBuilder.append(makeString("        case ", member.get().value(), ": break;\n"));
+                    stringBuilder.flexibleAppend("        case ", member.get().value(), ": break;\n");
                 }
                 ASSERT_UNUSED(hasZeroCase, hasZeroCase);
                 stringBuilder.append("        default: x = 0; break; }\n");
             }
         }
 
                 }
                 ASSERT_UNUSED(hasZeroCase, hasZeroCase);
                 stringBuilder.append("        default: x = 0; break; }\n");
             }
         }
 
-        stringBuilder.append(makeString("    return static_cast<", metalReturnName, ">(x);\n"));
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            "    return static_cast<", metalReturnName, ">(x);\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -167,9 +171,11 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         ASSERT(nativeFunctionDeclaration.parameters().size() == 1);
         auto metalParameterName = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
         ASSERT(nativeFunctionDeclaration.parameters().size() == 1);
         auto metalParameterName = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
-        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " x) {\n"));
-        stringBuilder.append(makeString("    return static_cast<", metalReturnName, ">(x);\n"));
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " x) {\n"
+            "    return static_cast<", metalReturnName, ">(x);\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -182,16 +188,20 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         auto& unnamedParameterType = downcast<AST::UnnamedType>(parameterType);
         if (is<AST::ArrayType>(unnamedParameterType)) {
             auto& arrayParameterType = downcast<AST::ArrayType>(unnamedParameterType);
         auto& unnamedParameterType = downcast<AST::UnnamedType>(parameterType);
         if (is<AST::ArrayType>(unnamedParameterType)) {
             auto& arrayParameterType = downcast<AST::ArrayType>(unnamedParameterType);
-            stringBuilder.append(makeString("uint ", outputFunctionName, '(', metalParameterName, ") {\n"));
-            stringBuilder.append(makeString("    return ", arrayParameterType.numElements(), ";\n"));
-            stringBuilder.append("}\n");
+            stringBuilder.flexibleAppend(
+                "uint ", outputFunctionName, '(', metalParameterName, ") {\n"
+                "    return ", arrayParameterType.numElements(), ";\n"
+                "}\n"
+            );
             return stringBuilder.toString();
         }
 
         ASSERT(is<AST::ArrayReferenceType>(unnamedParameterType));
             return stringBuilder.toString();
         }
 
         ASSERT(is<AST::ArrayReferenceType>(unnamedParameterType));
-        stringBuilder.append(makeString("uint ", outputFunctionName, '(', metalParameterName, " v) {\n"));
-        stringBuilder.append(makeString("    return v.length;\n"));
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            "uint ", outputFunctionName, '(', metalParameterName, " v) {\n"
+            "    return v.length;\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -217,10 +227,12 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
             auto fieldName = nativeFunctionDeclaration.name().substring("operator."_str.length());
             fieldName = fieldName.substring(0, fieldName.length() - 1);
             auto metalFieldName = mangledFieldName(fieldName);
             auto fieldName = nativeFunctionDeclaration.name().substring("operator."_str.length());
             fieldName = fieldName.substring(0, fieldName.length() - 1);
             auto metalFieldName = mangledFieldName(fieldName);
-            stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " v, ", metalParameter2Name, " n) {\n"));
-            stringBuilder.append(makeString("    v.", metalFieldName, " = n;\n"));
-            stringBuilder.append(makeString("    return v;\n"));
-            stringBuilder.append("}\n");
+            stringBuilder.flexibleAppend(
+                metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " v, ", metalParameter2Name, " n) {\n"
+                "    v.", metalFieldName, " = n;\n"
+                "    return v;\n"
+                "}\n"
+            );
             return stringBuilder.toString();
         }
 
             return stringBuilder.toString();
         }
 
@@ -229,9 +241,11 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         auto metalParameterName = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
         auto metalFieldName = mangledFieldName(fieldName);
         auto metalParameterName = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
         auto metalFieldName = mangledFieldName(fieldName);
-        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " v) {\n"));
-        stringBuilder.append(makeString("    return v.", metalFieldName, ";\n"));
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " v) {\n"
+            "    return v.", metalFieldName, ";\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -253,9 +267,11 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         } else
             metalFieldName = fieldName;
 
         } else
             metalFieldName = fieldName;
 
-        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " v) {\n"));
-        stringBuilder.append(makeString("    return &(v->", metalFieldName, ");\n"));
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " v) {\n"
+            "    return &(v->", metalFieldName, ");\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -264,11 +280,13 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
         auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
-        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " v, ", metalParameter2Name, " n) {\n"));
         ASSERT(is<AST::ArrayReferenceType>(*nativeFunctionDeclaration.parameters()[0]->type()));
         ASSERT(is<AST::ArrayReferenceType>(*nativeFunctionDeclaration.parameters()[0]->type()));
-        stringBuilder.append("    if (n < v.length) return &(v.pointer[n]);\n");
-        stringBuilder.append("    return nullptr;\n");
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " v, ", metalParameter2Name, " n) {\n"
+            "    if (n < v.length) return &(v.pointer[n]);\n"
+            "    return nullptr;\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -295,17 +313,21 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         unsigned numberOfRows = numberOfMatrixRows();
         unsigned numberOfColumns = numberOfMatrixColumns();
 
         unsigned numberOfRows = numberOfMatrixRows();
         unsigned numberOfColumns = numberOfMatrixColumns();
 
-        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " m, ", metalParameter2Name, " i) {\n"));
-        stringBuilder.append(makeString("    if (i >= ", numberOfRows, ") return ", metalReturnName, "(0);\n"));
-        stringBuilder.append(makeString("    ", metalReturnName, " result;\n"));
-        stringBuilder.append("    result[0] = m[i];\n");
-        stringBuilder.append(makeString("    result[1] = m[i + ", numberOfRows, "];\n"));
+        stringBuilder.flexibleAppend(
+            metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " m, ", metalParameter2Name, " i) {\n"
+            "    if (i >= ", numberOfRows, ") return ", metalReturnName, "(0);\n"
+            "    ", metalReturnName, " result;\n"
+            "    result[0] = m[i];\n"
+            "    result[1] = m[i + ", numberOfRows, "];\n"
+        );
         if (numberOfColumns >= 3)
         if (numberOfColumns >= 3)
-            stringBuilder.append(makeString("    result[2] = m[i + ", numberOfRows * 2, "];\n"));
+            stringBuilder.flexibleAppend("    result[2] = m[i + ", numberOfRows * 2, "];\n");
         if (numberOfColumns >= 4)
         if (numberOfColumns >= 4)
-            stringBuilder.append(makeString("    result[3] = m[i + ", numberOfRows * 3, "];\n"));
-        stringBuilder.append("    return result;\n");
-        stringBuilder.append("}\n");
+            stringBuilder.flexibleAppend("    result[3] = m[i + ", numberOfRows * 3, "];\n");
+        stringBuilder.append(
+            "    return result;\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -319,16 +341,20 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         unsigned numberOfRows = numberOfMatrixRows();
         unsigned numberOfColumns = numberOfMatrixColumns();
 
         unsigned numberOfRows = numberOfMatrixRows();
         unsigned numberOfColumns = numberOfMatrixColumns();
 
-        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " m, ", metalParameter2Name, " i, ", metalParameter3Name, " v) {\n"));
-        stringBuilder.append(makeString("    if (i >= ", numberOfRows, ") return m;\n"));
-        stringBuilder.append(makeString("    m[i] = v[0];\n"));
-        stringBuilder.append(makeString("    m[i + ", numberOfRows, "] = v[1];\n"));
+        stringBuilder.flexibleAppend(
+            metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " m, ", metalParameter2Name, " i, ", metalParameter3Name, " v) {\n"
+            "    if (i >= ", numberOfRows, ") return m;\n"
+            "    m[i] = v[0];\n"
+            "    m[i + ", numberOfRows, "] = v[1];\n"
+        );
         if (numberOfColumns >= 3)
         if (numberOfColumns >= 3)
-            stringBuilder.append(makeString("    m[i + ", numberOfRows * 2, "] = v[2];\n"));
+            stringBuilder.flexibleAppend("    m[i + ", numberOfRows * 2, "] = v[2];\n");
         if (numberOfColumns >= 4)
         if (numberOfColumns >= 4)
-            stringBuilder.append(makeString("    m[i + ", numberOfRows * 3, "] = v[3];\n"));
-        stringBuilder.append("    return m;");
-        stringBuilder.append("}\n");
+            stringBuilder.flexibleAppend("    m[i + ", numberOfRows * 3, "] = v[3];\n");
+        stringBuilder.append(
+            "    return m;"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -337,9 +363,11 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
             auto operatorName = nativeFunctionDeclaration.name().substring("operator"_str.length());
             auto metalParameterName = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
             auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
             auto operatorName = nativeFunctionDeclaration.name().substring("operator"_str.length());
             auto metalParameterName = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
             auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
-            stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " x) {\n"));
-            stringBuilder.append(makeString("    return ", operatorName, "x;\n"));
-            stringBuilder.append("}\n");
+            stringBuilder.flexibleAppend(
+                metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " x) {\n"
+                "    return ", operatorName, "x;\n"
+                "}\n"
+            );
             return stringBuilder.toString();
         }
 
             return stringBuilder.toString();
         }
 
@@ -348,9 +376,11 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
         auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
-        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " x, ", metalParameter2Name, " y) {\n"));
-        stringBuilder.append(makeString("    return x ", operatorName, " y;\n"));
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " x, ", metalParameter2Name, " y) {\n"
+            "    return x ", operatorName, " y;\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -381,9 +411,11 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         ASSERT(nativeFunctionDeclaration.parameters().size() == 1);
         auto metalParameterName = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
         ASSERT(nativeFunctionDeclaration.parameters().size() == 1);
         auto metalParameterName = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
-        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " x) {\n"));
-        stringBuilder.append(makeString("    return ", mapFunctionName(nativeFunctionDeclaration.name()), "(x);\n"));
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " x) {\n"
+            "    return ", mapFunctionName(nativeFunctionDeclaration.name()), "(x);\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -392,35 +424,43 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
         auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
-        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " x, ", metalParameter2Name, " y) {\n"));
-        stringBuilder.append(makeString("    return ", nativeFunctionDeclaration.name(), "(x, y);\n"));
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " x, ", metalParameter2Name, " y) {\n"
+            "    return ", nativeFunctionDeclaration.name(), "(x, y);\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
     if (nativeFunctionDeclaration.name() == "AllMemoryBarrierWithGroupSync") {
         ASSERT(!nativeFunctionDeclaration.parameters().size());
         return stringBuilder.toString();
     }
 
     if (nativeFunctionDeclaration.name() == "AllMemoryBarrierWithGroupSync") {
         ASSERT(!nativeFunctionDeclaration.parameters().size());
-        stringBuilder.append(makeString("void ", outputFunctionName, "() {\n"));
-        stringBuilder.append("    threadgroup_barrier(mem_flags::mem_device);\n");
-        stringBuilder.append("    threadgroup_barrier(mem_flags::mem_threadgroup);\n");
-        stringBuilder.append("    threadgroup_barrier(mem_flags::mem_texture);\n");
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            "void ", outputFunctionName, "() {\n"
+            "    threadgroup_barrier(mem_flags::mem_device);\n"
+            "    threadgroup_barrier(mem_flags::mem_threadgroup);\n"
+            "    threadgroup_barrier(mem_flags::mem_texture);\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
     if (nativeFunctionDeclaration.name() == "DeviceMemoryBarrierWithGroupSync") {
         ASSERT(!nativeFunctionDeclaration.parameters().size());
         return stringBuilder.toString();
     }
 
     if (nativeFunctionDeclaration.name() == "DeviceMemoryBarrierWithGroupSync") {
         ASSERT(!nativeFunctionDeclaration.parameters().size());
-        stringBuilder.append(makeString("void ", outputFunctionName, "() {\n"));
-        stringBuilder.append("    threadgroup_barrier(mem_flags::mem_device);\n");
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            "void ", outputFunctionName, "() {\n"
+            "    threadgroup_barrier(mem_flags::mem_device);\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
     if (nativeFunctionDeclaration.name() == "GroupMemoryBarrierWithGroupSync") {
         ASSERT(!nativeFunctionDeclaration.parameters().size());
         return stringBuilder.toString();
     }
 
     if (nativeFunctionDeclaration.name() == "GroupMemoryBarrierWithGroupSync") {
         ASSERT(!nativeFunctionDeclaration.parameters().size());
-        stringBuilder.append(makeString("void ", outputFunctionName, "() {\n"));
-        stringBuilder.append("    threadgroup_barrier(mem_flags::mem_threadgroup);\n");
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            "void ", outputFunctionName, "() {\n"
+            "    threadgroup_barrier(mem_flags::mem_threadgroup);\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -435,10 +475,12 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
             auto& fourthArgumentPointer = downcast<AST::PointerType>(*nativeFunctionDeclaration.parameters()[3]->type());
             auto fourthArgumentAddressSpace = fourthArgumentPointer.addressSpace();
             auto fourthArgumentPointee = typeNamer.mangledNameForType(fourthArgumentPointer.elementType());
             auto& fourthArgumentPointer = downcast<AST::PointerType>(*nativeFunctionDeclaration.parameters()[3]->type());
             auto fourthArgumentAddressSpace = fourthArgumentPointer.addressSpace();
             auto fourthArgumentPointee = typeNamer.mangledNameForType(fourthArgumentPointer.elementType());
-            stringBuilder.append(makeString("void ", outputFunctionName, '(', toString(firstArgumentAddressSpace), ' ', firstArgumentPointee, "* object, ", secondArgument, " compare, ", thirdArgument, " desired, ", toString(fourthArgumentAddressSpace), ' ', fourthArgumentPointee, "* out) {\n"));
-            stringBuilder.append("    atomic_compare_exchange_weak_explicit(object, &compare, desired, memory_order_relaxed, memory_order_relaxed);\n");
-            stringBuilder.append("    *out = compare;\n");
-            stringBuilder.append("}\n");
+            stringBuilder.flexibleAppend(
+                "void ", outputFunctionName, '(', toString(firstArgumentAddressSpace), ' ', firstArgumentPointee, "* object, ", secondArgument, " compare, ", thirdArgument, " desired, ", toString(fourthArgumentAddressSpace), ' ', fourthArgumentPointee, "* out) {\n"
+                "    atomic_compare_exchange_weak_explicit(object, &compare, desired, memory_order_relaxed, memory_order_relaxed);\n"
+                "    *out = compare;\n"
+                "}\n"
+            );
             return stringBuilder.toString();
         }
 
             return stringBuilder.toString();
         }
 
@@ -451,9 +493,11 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         auto thirdArgumentAddressSpace = thirdArgumentPointer.addressSpace();
         auto thirdArgumentPointee = typeNamer.mangledNameForType(thirdArgumentPointer.elementType());
         auto name = atomicName(nativeFunctionDeclaration.name().substring("Interlocked"_str.length()));
         auto thirdArgumentAddressSpace = thirdArgumentPointer.addressSpace();
         auto thirdArgumentPointee = typeNamer.mangledNameForType(thirdArgumentPointer.elementType());
         auto name = atomicName(nativeFunctionDeclaration.name().substring("Interlocked"_str.length()));
-        stringBuilder.append(makeString("void ", outputFunctionName, '(', toString(firstArgumentAddressSpace), ' ', firstArgumentPointee, "* object, ", secondArgument, " operand, ", toString(thirdArgumentAddressSpace), ' ', thirdArgumentPointee, "* out) {\n"));
-        stringBuilder.append(makeString("    *out = atomic_", name, "_explicit(object, operand, memory_order_relaxed);\n"));
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            "void ", outputFunctionName, '(', toString(firstArgumentAddressSpace), ' ', firstArgumentPointee, "* object, ", secondArgument, " operand, ", toString(thirdArgumentAddressSpace), ' ', thirdArgumentPointee, "* out) {\n"
+            "    *out = atomic_", name, "_explicit(object, operand, memory_order_relaxed);\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -473,23 +517,27 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         if (nativeFunctionDeclaration.parameters().size() == 4)
             metalParameter4Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[3]->type());
         auto metalReturnName = typeNamer.mangledNameForType(returnType);
         if (nativeFunctionDeclaration.parameters().size() == 4)
             metalParameter4Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[3]->type());
         auto metalReturnName = typeNamer.mangledNameForType(returnType);
-        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " theTexture, ", metalParameter2Name, " theSampler, ", metalParameter3Name, " location"));
+        stringBuilder.flexibleAppend(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " theTexture, ", metalParameter2Name, " theSampler, ", metalParameter3Name, " location");
         if (!metalParameter4Name.isNull())
         if (!metalParameter4Name.isNull())
-            stringBuilder.append(makeString(", ", metalParameter4Name, " offset"));
-        stringBuilder.append(") {\n");
-        stringBuilder.append("    return theTexture.sample(theSampler, ");
+            stringBuilder.flexibleAppend(", ", metalParameter4Name, " offset");
+        stringBuilder.append(
+            ") {\n"
+            "    return theTexture.sample(theSampler, "
+        );
         if (textureType.isTextureArray()) {
             ASSERT(locationVectorLength > 1);
         if (textureType.isTextureArray()) {
             ASSERT(locationVectorLength > 1);
-            stringBuilder.append(makeString("location.", "xyzw"_str.substring(0, locationVectorLength - 1), ", location.", "xyzw"_str.substring(locationVectorLength - 1, 1)));
+            stringBuilder.flexibleAppend("location.", "xyzw"_str.substring(0, locationVectorLength - 1), ", location.", "xyzw"_str.substring(locationVectorLength - 1, 1));
         } else
             stringBuilder.append("location");
         if (!metalParameter4Name.isNull())
             stringBuilder.append(", offset");
         stringBuilder.append(")");
         if (!textureType.isDepthTexture())
         } else
             stringBuilder.append("location");
         if (!metalParameter4Name.isNull())
             stringBuilder.append(", offset");
         stringBuilder.append(")");
         if (!textureType.isDepthTexture())
-            stringBuilder.append(makeString(".", "xyzw"_str.substring(0, returnVectorLength)));
-        stringBuilder.append(";\n");
-        stringBuilder.append("}\n");
+            stringBuilder.flexibleAppend(".", "xyzw"_str.substring(0, returnVectorLength));
+        stringBuilder.append(
+            ";\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -505,37 +553,41 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         auto metalParameter1Name = typeNamer.mangledNameForType(textureType);
         auto metalParameter2Name = typeNamer.mangledNameForType(locationType);
         auto metalReturnName = typeNamer.mangledNameForType(returnType);
         auto metalParameter1Name = typeNamer.mangledNameForType(textureType);
         auto metalParameter2Name = typeNamer.mangledNameForType(locationType);
         auto metalReturnName = typeNamer.mangledNameForType(returnType);
-        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " theTexture, ", metalParameter2Name, " location) {\n"));
+        stringBuilder.flexibleAppend(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " theTexture, ", metalParameter2Name, " location) {\n");
         if (textureType.isTextureArray()) {
             ASSERT(locationVectorLength > 1);
             String dimensions[] = { "width"_str, "height"_str, "depth"_str };
             for (int i = 0; i < locationVectorLength - 1; ++i) {
                 auto suffix = "xyzw"_str.substring(i, 1);
         if (textureType.isTextureArray()) {
             ASSERT(locationVectorLength > 1);
             String dimensions[] = { "width"_str, "height"_str, "depth"_str };
             for (int i = 0; i < locationVectorLength - 1; ++i) {
                 auto suffix = "xyzw"_str.substring(i, 1);
-                stringBuilder.append(makeString("    if (location.", suffix, " < 0 || static_cast<uint32_t>(location.", suffix, ") >= theTexture.get_", dimensions[i], "()) return ", metalReturnName, "(0);\n"));
+                stringBuilder.flexibleAppend("    if (location.", suffix, " < 0 || static_cast<uint32_t>(location.", suffix, ") >= theTexture.get_", dimensions[i], "()) return ", metalReturnName, "(0);\n");
             }
             auto suffix = "xyzw"_str.substring(locationVectorLength - 1, 1);
             }
             auto suffix = "xyzw"_str.substring(locationVectorLength - 1, 1);
-            stringBuilder.append(makeString("    if (location.", suffix, " < 0 || static_cast<uint32_t>(location.", suffix, ") >= theTexture.get_array_size()) return ", metalReturnName, "(0);\n"));
+            stringBuilder.flexibleAppend("    if (location.", suffix, " < 0 || static_cast<uint32_t>(location.", suffix, ") >= theTexture.get_array_size()) return ", metalReturnName, "(0);\n");
         } else {
             if (locationVectorLength == 1)
         } else {
             if (locationVectorLength == 1)
-                stringBuilder.append(makeString("    if (location < 0 || static_cast<uint32_t>(location) >= theTexture.get_width()) return ", metalReturnName, "(0);\n"));
+                stringBuilder.flexibleAppend("    if (location < 0 || static_cast<uint32_t>(location) >= theTexture.get_width()) return ", metalReturnName, "(0);\n");
             else {
             else {
-                stringBuilder.append(makeString("    if (location.x < 0 || static_cast<uint32_t>(location.x) >= theTexture.get_width()) return ", metalReturnName, "(0);\n"));
-                stringBuilder.append(makeString("    if (location.y < 0 || static_cast<uint32_t>(location.y) >= theTexture.get_height()) return ", metalReturnName, "(0);\n"));
+                stringBuilder.flexibleAppend(
+                    "    if (location.x < 0 || static_cast<uint32_t>(location.x) >= theTexture.get_width()) return ", metalReturnName, "(0);\n"
+                    "    if (location.y < 0 || static_cast<uint32_t>(location.y) >= theTexture.get_height()) return ", metalReturnName, "(0);\n"
+                );
                 if (locationVectorLength >= 3)
                 if (locationVectorLength >= 3)
-                    stringBuilder.append(makeString("    if (location.z < 0 || static_cast<uint32_t>(location.z) >= theTexture.get_depth()) return ", metalReturnName, "(0);\n"));
+                    stringBuilder.flexibleAppend("    if (location.z < 0 || static_cast<uint32_t>(location.z) >= theTexture.get_depth()) return ", metalReturnName, "(0);\n");
             }
         }
         stringBuilder.append("    return theTexture.read(");
         if (textureType.isTextureArray()) {
             ASSERT(locationVectorLength > 1);
             }
         }
         stringBuilder.append("    return theTexture.read(");
         if (textureType.isTextureArray()) {
             ASSERT(locationVectorLength > 1);
-            stringBuilder.append(makeString("uint", vectorSuffix(locationVectorLength - 1), "(location.", "xyzw"_str.substring(0, locationVectorLength - 1), "), uint(location.", "xyzw"_str.substring(locationVectorLength - 1, 1), ")"));
+            stringBuilder.flexibleAppend("uint", vectorSuffix(locationVectorLength - 1), "(location.", "xyzw"_str.substring(0, locationVectorLength - 1), "), uint(location.", "xyzw"_str.substring(locationVectorLength - 1, 1), ')');
         } else
         } else
-            stringBuilder.append(makeString("uint", vectorSuffix(locationVectorLength), "(location)"));
-        stringBuilder.append(")");
+            stringBuilder.flexibleAppend("uint", vectorSuffix(locationVectorLength), "(location)");
+        stringBuilder.append(')');
         if (!textureType.isDepthTexture())
         if (!textureType.isDepthTexture())
-            stringBuilder.append(makeString(".", "xyzw"_str.substring(0, returnVectorLength)));
-        stringBuilder.append(";\n");
-        stringBuilder.append("}\n");
+            stringBuilder.flexibleAppend('.', "xyzw"_str.substring(0, returnVectorLength));
+        stringBuilder.append(
+            ";\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -543,9 +595,11 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         ASSERT(nativeFunctionDeclaration.parameters().size() == 1);
         auto metalParameterName = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
         ASSERT(nativeFunctionDeclaration.parameters().size() == 1);
         auto metalParameterName = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
-        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " x) {\n"));
-        stringBuilder.append("    return atomic_load_explicit(x, memory_order_relaxed);\n");
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend(
+            metalReturnName, ' ', outputFunctionName, '(', metalParameterName, " x) {\n"
+            "    return atomic_load_explicit(x, memory_order_relaxed);\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -553,9 +607,9 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         ASSERT(nativeFunctionDeclaration.parameters().size() == 2);
         auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type());
         ASSERT(nativeFunctionDeclaration.parameters().size() == 2);
         auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
         auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type());
-        stringBuilder.append(makeString("void ", outputFunctionName, '(', metalParameter1Name, " x, ", metalParameter2Name, " y) {\n"));
-        stringBuilder.append("    atomic_store_explicit(x, y, memory_order_relaxed);\n");
-        stringBuilder.append("}\n");
+        stringBuilder.flexibleAppend("void ", outputFunctionName, '(', metalParameter1Name, " x, ", metalParameter2Name, " y) {\n"
+            "    atomic_store_explicit(x, y, memory_order_relaxed);\n"
+            "}\n");
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
@@ -590,45 +644,55 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         ASSERT(index == nativeFunctionDeclaration.parameters().size());
 
         auto metalParameter1Name = typeNamer.mangledNameForType(textureType);
         ASSERT(index == nativeFunctionDeclaration.parameters().size());
 
         auto metalParameter1Name = typeNamer.mangledNameForType(textureType);
-        stringBuilder.append(makeString("void ", outputFunctionName, '(', metalParameter1Name, " theTexture"));
+        stringBuilder.flexibleAppend("void ", outputFunctionName, '(', metalParameter1Name, " theTexture");
         if (!textureType.isWritableTexture() && textureType.textureDimension() != 1)
             stringBuilder.append(", uint mipLevel");
         if (!textureType.isWritableTexture() && textureType.textureDimension() != 1)
             stringBuilder.append(", uint mipLevel");
-        stringBuilder.append(makeString(", ", widthTypeName, " width"));
+        stringBuilder.flexibleAppend(", ", widthTypeName, " width");
         if (!heightTypeName.isNull())
         if (!heightTypeName.isNull())
-            stringBuilder.append(makeString(", ", heightTypeName, " height"));
+            stringBuilder.flexibleAppend(", ", heightTypeName, " height");
         if (!depthTypeName.isNull())
         if (!depthTypeName.isNull())
-            stringBuilder.append(makeString(", ", depthTypeName, " depth"));
+            stringBuilder.flexibleAppend(", ", depthTypeName, " depth");
         if (!elementsTypeName.isNull())
         if (!elementsTypeName.isNull())
-            stringBuilder.append(makeString(", ", elementsTypeName, " elements"));
+            stringBuilder.flexibleAppend(", ", elementsTypeName, " elements");
         if (!numberOfLevelsTypeName.isNull())
         if (!numberOfLevelsTypeName.isNull())
-            stringBuilder.append(makeString(", ", numberOfLevelsTypeName, " numberOfLevels"));
-        stringBuilder.append(") {\n");
-        stringBuilder.append("    if (width)\n");
-        stringBuilder.append("        *width = theTexture.get_width(");
+            stringBuilder.flexibleAppend(", ", numberOfLevelsTypeName, " numberOfLevels");
+        stringBuilder.append(
+            ") {\n"
+            "    if (width)\n"
+            "        *width = theTexture.get_width("
+        );
         if (!textureType.isWritableTexture() && textureType.textureDimension() != 1)
             stringBuilder.append("mipLevel");
         stringBuilder.append(");\n");
         if (!heightTypeName.isNull()) {
         if (!textureType.isWritableTexture() && textureType.textureDimension() != 1)
             stringBuilder.append("mipLevel");
         stringBuilder.append(");\n");
         if (!heightTypeName.isNull()) {
-            stringBuilder.append("    if (height)\n");
-            stringBuilder.append("        *height = theTexture.get_height(");
+            stringBuilder.append(
+                "    if (height)\n"
+                "        *height = theTexture.get_height("
+            );
             if (!textureType.isWritableTexture() && textureType.textureDimension() != 1)
                 stringBuilder.append("mipLevel");
             stringBuilder.append(");\n");
         }
         if (!depthTypeName.isNull()) {
             if (!textureType.isWritableTexture() && textureType.textureDimension() != 1)
                 stringBuilder.append("mipLevel");
             stringBuilder.append(");\n");
         }
         if (!depthTypeName.isNull()) {
-            stringBuilder.append("    if (depth)\n");
-            stringBuilder.append("        *depth = theTexture.get_depth(");
+            stringBuilder.append(
+                "    if (depth)\n"
+                "        *depth = theTexture.get_depth("
+            );
             if (!textureType.isWritableTexture() && textureType.textureDimension() != 1)
                 stringBuilder.append("mipLevel");
             stringBuilder.append(");\n");
         }
         if (!elementsTypeName.isNull()) {
             if (!textureType.isWritableTexture() && textureType.textureDimension() != 1)
                 stringBuilder.append("mipLevel");
             stringBuilder.append(");\n");
         }
         if (!elementsTypeName.isNull()) {
-            stringBuilder.append("    if (elements)\n");
-            stringBuilder.append("        *elements = theTexture.get_array_size();\n");
+            stringBuilder.append(
+                "    if (elements)\n"
+                "        *elements = theTexture.get_array_size();\n"
+            );
         }
         if (!numberOfLevelsTypeName.isNull()) {
         }
         if (!numberOfLevelsTypeName.isNull()) {
-            stringBuilder.append("    if (numberOfLevels)\n");
-            stringBuilder.append("        *numberOfLevels = theTexture.get_num_mip_levels();\n");
+            stringBuilder.append(
+                "    if (numberOfLevels)\n"
+                "        *numberOfLevels = theTexture.get_num_mip_levels();\n"
+            );
         }
         stringBuilder.append("}\n");
         return stringBuilder.toString();
         }
         stringBuilder.append("}\n");
         return stringBuilder.toString();
@@ -683,37 +747,41 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         auto metalParameter2Name = typeNamer.mangledNameForType(itemType);
         auto metalParameter3Name = typeNamer.mangledNameForType(locationType);
         auto metalInnerTypeName = typeNamer.mangledNameForType(itemVectorInnerType);
         auto metalParameter2Name = typeNamer.mangledNameForType(itemType);
         auto metalParameter3Name = typeNamer.mangledNameForType(locationType);
         auto metalInnerTypeName = typeNamer.mangledNameForType(itemVectorInnerType);
-        stringBuilder.append(makeString("void ", outputFunctionName, '(', metalParameter1Name, " theTexture, ", metalParameter2Name, " item, ", metalParameter3Name, " location) {\n"));
+        stringBuilder.flexibleAppend("void ", outputFunctionName, '(', metalParameter1Name, " theTexture, ", metalParameter2Name, " item, ", metalParameter3Name, " location) {\n");
         if (textureType.isTextureArray()) {
             ASSERT(locationVectorLength > 1);
             String dimensions[] = { "width"_str, "height"_str, "depth"_str };
             for (int i = 0; i < locationVectorLength - 1; ++i) {
                 auto suffix = "xyzw"_str.substring(i, 1);
         if (textureType.isTextureArray()) {
             ASSERT(locationVectorLength > 1);
             String dimensions[] = { "width"_str, "height"_str, "depth"_str };
             for (int i = 0; i < locationVectorLength - 1; ++i) {
                 auto suffix = "xyzw"_str.substring(i, 1);
-                stringBuilder.append(makeString("    if (location.", suffix, " >= theTexture.get_", dimensions[i], "()) return;\n"));
+                stringBuilder.flexibleAppend("    if (location.", suffix, " >= theTexture.get_", dimensions[i], "()) return;\n");
             }
             auto suffix = "xyzw"_str.substring(locationVectorLength - 1, 1);
             }
             auto suffix = "xyzw"_str.substring(locationVectorLength - 1, 1);
-            stringBuilder.append(makeString("    if (location.", suffix, " >= theTexture.get_array_size()) return;\n"));
+            stringBuilder.flexibleAppend("    if (location.", suffix, " >= theTexture.get_array_size()) return;\n");
         } else {
             if (locationVectorLength == 1)
         } else {
             if (locationVectorLength == 1)
-                stringBuilder.append(makeString("    if (location >= theTexture.get_width()) return;\n"));
+                stringBuilder.append("    if (location >= theTexture.get_width()) return;\n");
             else {
             else {
-                stringBuilder.append(makeString("    if (location.x >= theTexture.get_width()) return;\n"));
-                stringBuilder.append(makeString("    if (location.y >= theTexture.get_height()) return;\n"));
+                stringBuilder.append(
+                    "    if (location.x >= theTexture.get_width()) return;\n"
+                    "    if (location.y >= theTexture.get_height()) return;\n"
+                );
                 if (locationVectorLength >= 3)
                 if (locationVectorLength >= 3)
-                    stringBuilder.append(makeString("    if (location.z >= theTexture.get_depth()) return;\n"));
+                    stringBuilder.append("    if (location.z >= theTexture.get_depth()) return;\n");
             }
         }
             }
         }
-        stringBuilder.append(makeString("    theTexture.write(vec<", metalInnerTypeName, ", 4>(item"));
+        stringBuilder.flexibleAppend("    theTexture.write(vec<", metalInnerTypeName, ", 4>(item");
         for (int i = 0; i < 4 - itemVectorLength; ++i)
             stringBuilder.append(", 0");
         stringBuilder.append("), ");
         if (textureType.isTextureArray()) {
             ASSERT(locationVectorLength > 1);
         for (int i = 0; i < 4 - itemVectorLength; ++i)
             stringBuilder.append(", 0");
         stringBuilder.append("), ");
         if (textureType.isTextureArray()) {
             ASSERT(locationVectorLength > 1);
-            stringBuilder.append(makeString("uint", vectorSuffix(locationVectorLength - 1), "(location.", "xyzw"_str.substring(0, locationVectorLength - 1), "), uint(location.", "xyzw"_str.substring(locationVectorLength - 1, 1), ")"));
+            stringBuilder.flexibleAppend("uint", vectorSuffix(locationVectorLength - 1), "(location.", "xyzw"_str.substring(0, locationVectorLength - 1), "), uint(location.", "xyzw"_str.substring(locationVectorLength - 1, 1), ')');
         } else
         } else
-            stringBuilder.append(makeString("uint", vectorSuffix(locationVectorLength), "(location)"));
-        stringBuilder.append(");\n");
-        stringBuilder.append("}\n");
+            stringBuilder.flexibleAppend("uint", vectorSuffix(locationVectorLength), "(location)");
+        stringBuilder.append(
+            ");\n"
+            "}\n"
+        );
         return stringBuilder.toString();
     }
 
         return stringBuilder.toString();
     }
 
index b00ab57..c864ce1 100644 (file)
@@ -361,7 +361,7 @@ public:
 private:
     void visit(AST::StructureDefinition& structureDefinition)
     {
 private:
     void visit(AST::StructureDefinition& structureDefinition)
     {
-        m_stringBuilder.append(makeString("struct ", m_mangledNameForNamedType(structureDefinition), ";\n"));
+        m_stringBuilder.flexibleAppend("struct ", m_mangledNameForNamedType(structureDefinition), ";\n");
     }
 
     std::function<String(AST::NamedType&)> m_mangledNameForNamedType;
     }
 
     std::function<String(AST::NamedType&)> m_mangledNameForNamedType;
@@ -386,22 +386,24 @@ void TypeNamer::emitUnnamedTypeDefinition(BaseTypeNameNode& baseTypeNameNode, Ha
     if (is<ReferenceTypeNameNode>(baseTypeNameNode)) {
         auto& namedType = downcast<ReferenceTypeNameNode>(baseTypeNameNode).namedType();
         emitNamedTypeDefinition(namedType, emittedNamedTypes, emittedUnnamedTypes, stringBuilder);
     if (is<ReferenceTypeNameNode>(baseTypeNameNode)) {
         auto& namedType = downcast<ReferenceTypeNameNode>(baseTypeNameNode).namedType();
         emitNamedTypeDefinition(namedType, emittedNamedTypes, emittedUnnamedTypes, stringBuilder);
-        stringBuilder.append(makeString("typedef ", mangledNameForType(namedType), ' ', baseTypeNameNode.mangledName(), ";\n"));
+        stringBuilder.flexibleAppend("typedef ", mangledNameForType(namedType), ' ', baseTypeNameNode.mangledName(), ";\n");
     } else if (is<PointerTypeNameNode>(baseTypeNameNode)) {
         auto& pointerType = downcast<PointerTypeNameNode>(baseTypeNameNode);
         ASSERT(baseTypeNameNode.parent());
     } else if (is<PointerTypeNameNode>(baseTypeNameNode)) {
         auto& pointerType = downcast<PointerTypeNameNode>(baseTypeNameNode);
         ASSERT(baseTypeNameNode.parent());
-        stringBuilder.append(makeString("typedef ", toString(pointerType.addressSpace()), " ", pointerType.parent()->mangledName(), "* ", pointerType.mangledName(), ";\n"));
+        stringBuilder.flexibleAppend("typedef ", toString(pointerType.addressSpace()), ' ', pointerType.parent()->mangledName(), "* ", pointerType.mangledName(), ";\n");
     } else if (is<ArrayReferenceTypeNameNode>(baseTypeNameNode)) {
         auto& arrayReferenceType = downcast<ArrayReferenceTypeNameNode>(baseTypeNameNode);
         ASSERT(baseTypeNameNode.parent());
     } else if (is<ArrayReferenceTypeNameNode>(baseTypeNameNode)) {
         auto& arrayReferenceType = downcast<ArrayReferenceTypeNameNode>(baseTypeNameNode);
         ASSERT(baseTypeNameNode.parent());
-        stringBuilder.append(makeString("struct ", arrayReferenceType.mangledName(), "{ \n"));
-        stringBuilder.append(makeString("    ", toString(arrayReferenceType.addressSpace()), " ", arrayReferenceType.parent()->mangledName(), "* pointer;\n"));
-        stringBuilder.append("    uint32_t length;\n");
-        stringBuilder.append("};\n");
+        stringBuilder.flexibleAppend(
+            "struct ", arrayReferenceType.mangledName(), "{ \n"
+            "    ", toString(arrayReferenceType.addressSpace()), ' ', arrayReferenceType.parent()->mangledName(), "* pointer;\n"
+            "    uint32_t length;\n"
+            "};\n"
+        );
     } else {
         auto& arrayType = downcast<ArrayTypeNameNode>(baseTypeNameNode);
         ASSERT(baseTypeNameNode.parent());
     } else {
         auto& arrayType = downcast<ArrayTypeNameNode>(baseTypeNameNode);
         ASSERT(baseTypeNameNode.parent());
-        stringBuilder.append(makeString("typedef array<", arrayType.parent()->mangledName(), ", ", arrayType.numElements(), "> ", arrayType.mangledName(), ";\n"));
+        stringBuilder.flexibleAppend("typedef array<", arrayType.parent()->mangledName(), ", ", arrayType.numElements(), "> ", arrayType.mangledName(), ";\n");
     }
     emittedUnnamedTypes.add(&baseTypeNameNode);
 }
     }
     emittedUnnamedTypes.add(&baseTypeNameNode);
 }
@@ -417,21 +419,21 @@ void TypeNamer::emitNamedTypeDefinition(AST::NamedType& namedType, HashSet<AST::
     if (is<AST::EnumerationDefinition>(namedType)) {
         auto& enumerationDefinition = downcast<AST::EnumerationDefinition>(namedType);
         auto& baseType = enumerationDefinition.type().unifyNode();
     if (is<AST::EnumerationDefinition>(namedType)) {
         auto& enumerationDefinition = downcast<AST::EnumerationDefinition>(namedType);
         auto& baseType = enumerationDefinition.type().unifyNode();
-        stringBuilder.append(makeString("enum class ", mangledNameForType(enumerationDefinition), " : ", mangledNameForType(downcast<AST::NamedType>(baseType)), " {\n"));
+        stringBuilder.flexibleAppend("enum class ", mangledNameForType(enumerationDefinition), " : ", mangledNameForType(downcast<AST::NamedType>(baseType)), " {\n");
         for (auto& enumerationMember : enumerationDefinition.enumerationMembers())
         for (auto& enumerationMember : enumerationDefinition.enumerationMembers())
-            stringBuilder.append(makeString("    ", mangledNameForEnumerationMember(enumerationMember), " = ", enumerationMember.get().value(), ",\n"));
+            stringBuilder.flexibleAppend("    ", mangledNameForEnumerationMember(enumerationMember), " = ", enumerationMember.get().value(), ",\n");
         stringBuilder.append("};\n");
     } else if (is<AST::NativeTypeDeclaration>(namedType)) {
         // Native types already have definitions. There's nothing to do.
     } else if (is<AST::StructureDefinition>(namedType)) {
         auto& structureDefinition = downcast<AST::StructureDefinition>(namedType);
         stringBuilder.append("};\n");
     } else if (is<AST::NativeTypeDeclaration>(namedType)) {
         // Native types already have definitions. There's nothing to do.
     } else if (is<AST::StructureDefinition>(namedType)) {
         auto& structureDefinition = downcast<AST::StructureDefinition>(namedType);
-        stringBuilder.append(makeString("struct ", mangledNameForType(structureDefinition), " {\n"));
+        stringBuilder.flexibleAppend("struct ", mangledNameForType(structureDefinition), " {\n");
         for (auto& structureElement : structureDefinition.structureElements())
         for (auto& structureElement : structureDefinition.structureElements())
-            stringBuilder.append(makeString("    ", mangledNameForType(structureElement.type()), ' ', mangledNameForStructureElement(structureElement), ";\n"));
+            stringBuilder.flexibleAppend("    ", mangledNameForType(structureElement.type()), ' ', mangledNameForStructureElement(structureElement), ";\n");
         stringBuilder.append("};\n");
     } else {
         auto& typeDefinition = downcast<AST::TypeDefinition>(namedType);
         stringBuilder.append("};\n");
     } else {
         auto& typeDefinition = downcast<AST::TypeDefinition>(namedType);
-        stringBuilder.append(makeString("typedef ", mangledNameForType(typeDefinition.type()), ' ', mangledNameForType(typeDefinition), ";\n"));
+        stringBuilder.flexibleAppend("typedef ", mangledNameForType(typeDefinition.type()), ' ', mangledNameForType(typeDefinition), ";\n");
     }
     emittedNamedTypes.add(&namedType);
 }
     }
     emittedNamedTypes.add(&namedType);
 }
@@ -487,11 +489,7 @@ String TypeNamer::mangledNameForStructureElement(AST::StructureElement& structur
 String TypeNamer::metalTypes()
 {
     Visitor::visit(m_program);
 String TypeNamer::metalTypes()
 {
     Visitor::visit(m_program);
-    StringBuilder stringBuilder;
-    stringBuilder.append(metalTypeDeclarations());
-    stringBuilder.append('\n');
-    stringBuilder.append(metalTypeDefinitions());
-    return stringBuilder.toString();
+    return makeString(metalTypeDeclarations(), '\n', metalTypeDefinitions());
 }
 
 } // namespace Metal
 }
 
 } // namespace Metal
index 5cfbd77..04069b8 100644 (file)
@@ -158,8 +158,7 @@ struct Types {
 
     static void appendNameTo(StringBuilder& builder)
     {
 
     static void appendNameTo(StringBuilder& builder)
     {
-        builder.append(Token::typeName(t));
-        builder.append(", ");
+        builder.flexibleAppend(Token::typeName(t), ", ");
         Types<ts...>::appendNameTo(builder);
     }
 };
         Types<ts...>::appendNameTo(builder);
     }
 };
index ea4e37c..8ff9f0f 100644 (file)
@@ -1367,14 +1367,12 @@ void RenderLayerCompositor::logLayerInfo(const RenderLayer& layer, const char* p
     absoluteBounds.move(layer.offsetFromAncestor(m_renderView.layer()));
     
     StringBuilder logString;
     absoluteBounds.move(layer.offsetFromAncestor(m_renderView.layer()));
     
     StringBuilder logString;
-    logString.append(makeString(pad(' ', 12 + depth * 2, hex(reinterpret_cast<uintptr_t>(&layer))), " id ", backing->graphicsLayer()->primaryLayerID(), " (", FormattedNumber::fixedWidth(absoluteBounds.x().toFloat(), 3), ',', FormattedNumber::fixedWidth(absoluteBounds.y().toFloat(), 3), '-', FormattedNumber::fixedWidth(absoluteBounds.maxX().toFloat(), 3), ',', FormattedNumber::fixedWidth(absoluteBounds.maxY().toFloat(), 3), ") ", FormattedNumber::fixedWidth(backing->backingStoreMemoryEstimate() / 1024, 2), "KB"));
+    logString.flexibleAppend(pad(' ', 12 + depth * 2, hex(reinterpret_cast<uintptr_t>(&layer))), " id ", backing->graphicsLayer()->primaryLayerID(), " (", FormattedNumber::fixedWidth(absoluteBounds.x().toFloat(), 3), ',', FormattedNumber::fixedWidth(absoluteBounds.y().toFloat(), 3), '-', FormattedNumber::fixedWidth(absoluteBounds.maxX().toFloat(), 3), ',', FormattedNumber::fixedWidth(absoluteBounds.maxY().toFloat(), 3), ") ", FormattedNumber::fixedWidth(backing->backingStoreMemoryEstimate() / 1024, 2), "KB");
 
     if (!layer.renderer().style().hasAutoZIndex())
 
     if (!layer.renderer().style().hasAutoZIndex())
-        logString.append(makeString(" z-index: ", layer.renderer().style().zIndex()));
+        logString.flexibleAppend(" z-index: ", layer.renderer().style().zIndex());
 
 
-    logString.appendLiteral(" (");
-    logString.append(logReasonsForCompositing(layer));
-    logString.appendLiteral(") ");
+    logString.flexibleAppend(" (", logReasonsForCompositing(layer), ") ");
 
     if (backing->graphicsLayer()->contentsOpaque() || backing->paintsIntoCompositedAncestor() || backing->foregroundLayer() || backing->backgroundLayer()) {
         logString.append('[');
 
     if (backing->graphicsLayer()->contentsOpaque() || backing->paintsIntoCompositedAncestor() || backing->foregroundLayer() || backing->backgroundLayer()) {
         logString.append('[');
index 14c20e9..c7cc899 100644 (file)
@@ -5001,7 +5001,7 @@ String Internals::ongoingLoadsDescriptions() const
         builder.append('[');
 
         for (auto& info : platformStrategies()->loaderStrategy()->intermediateLoadInformationFromResourceLoadIdentifier(identifier))
         builder.append('[');
 
         for (auto& info : platformStrategies()->loaderStrategy()->intermediateLoadInformationFromResourceLoadIdentifier(identifier))
-            builder.append(makeString("[", (int)info.type, ",\"", info.request.url().string(), "\",\"", info.request.httpMethod(), "\",", info.response.httpStatusCode(), "]"));
+            builder.flexibleAppend('[', (int)info.type, ",\"", info.request.url().string(), "\",\"", info.request.httpMethod(), "\",", info.response.httpStatusCode(), ']');
 
         builder.append(']');
     }
 
         builder.append(']');
     }