initial commit
authorJacob Lifshay <programmerjake@gmail.com>
Fri, 26 May 2017 09:20:58 +0000 (02:20 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Fri, 26 May 2017 09:20:58 +0000 (02:20 -0700)
20 files changed:
.clang-format [new file with mode: 0644]
.gitignore [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
build/.cproject [new file with mode: 0644]
build/.project [new file with mode: 0644]
src/CMakeLists.txt [new file with mode: 0644]
src/demo/CMakeLists.txt [new file with mode: 0644]
src/demo/demo.cpp [new file with mode: 0644]
src/spirv/CMakeLists.txt [new file with mode: 0644]
src/spirv/spirv.cpp [new file with mode: 0644]
src/spirv/spirv.h [new file with mode: 0644]
src/util/CMakeLists.txt [new file with mode: 0644]
src/util/in_place.cpp [new file with mode: 0644]
src/util/in_place.h [new file with mode: 0644]
src/util/is_referenceable.cpp [new file with mode: 0644]
src/util/is_referenceable.h [new file with mode: 0644]
src/util/is_swappable.cpp [new file with mode: 0644]
src/util/is_swappable.h [new file with mode: 0644]
src/util/optional.cpp [new file with mode: 0644]
src/util/optional.h [new file with mode: 0644]

diff --git a/.clang-format b/.clang-format
new file mode 100644 (file)
index 0000000..c65d7a3
--- /dev/null
@@ -0,0 +1,65 @@
+---
+Language: Cpp
+BasedOnStyle: Google
+AccessModifierOffset: -4
+AlignAfterOpenBracket: true
+AlignConsecutiveAssignments: false
+AlignEscapedNewlinesLeft: true
+AlignOperands: true
+AlignTrailingComments: false
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: false
+BinPackParameters: false
+BreakBeforeBinaryOperators: NonAssignment
+BreakBeforeBraces: Allman
+BreakBeforeTernaryOperators: false
+BreakConstructorInitializersBeforeComma: false
+ColumnLimit: 100
+CommentPragmas:  '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat: false
+ForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IndentCaseLabels: false
+IndentWidth: 4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd:   ''
+MaxEmptyLinesToKeep: 2
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 4
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: false
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerAlignment: Right
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: Never
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInCStyleCastParentheses: false
+SpacesInContainerLiterals: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 8
+UseTab: Never
+...
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..d56ce4a
--- /dev/null
@@ -0,0 +1,8 @@
+/.metadata/
+/build/src/
+/build/CMakeFiles/
+cmake_install.cmake
+CMakeCache.txt
+Makefile
+/build/.settings/
+/test-files/test.spv
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e9ef5d7
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright 2017 Jacob Lifshay
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+project(vulkan-cpu CXX)
+if(NOT ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
+  message(FATAL_ERROR "compiler is not clang")
+endif()
+add_compile_options(-Wall)
+add_subdirectory(src)
diff --git a/build/.cproject b/build/.cproject
new file mode 100644 (file)
index 0000000..a89bc8a
--- /dev/null
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+       <storageModule moduleId="org.eclipse.cdt.core.settings">
+               <cconfiguration id="cdt.managedbuild.toolchain.llvm.clang.linux.base.443828109">
+                       <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.llvm.clang.linux.base.443828109" moduleId="org.eclipse.cdt.core.settings" name="Default">
+                               <externalSettings/>
+                               <extensions>
+                                       <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+                                       <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+                               </extensions>
+                       </storageModule>
+                       <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+                               <configuration artifactName="${ProjName}" buildProperties="" description="" id="cdt.managedbuild.toolchain.llvm.clang.linux.base.443828109" name="Default" parent="org.eclipse.cdt.build.core.emptycfg">
+                                       <folderInfo id="cdt.managedbuild.toolchain.llvm.clang.linux.base.443828109.1911715907" name="/" resourcePath="">
+                                               <toolChain id="cdt.managedbuild.toolchain.llvm.clang.linux.base.908241746" name="LLVM with Clang (Linux)" superClass="cdt.managedbuild.toolchain.llvm.clang.linux.base">
+                                                       <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.llvm.platform.base.273786633" isAbstract="true" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.llvm.platform.base"/>
+                                                       <builder id="cdt.managedbuild.toolchain.llvm.clang.linux.base.443828109.1656164828" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
+                                                       <tool id="cdt.managedbuild.tool.llvm.assembler.base.668399128" name="LLVM assembler" superClass="cdt.managedbuild.tool.llvm.assembler.base"/>
+                                                       <tool id="cdt.managedbuild.tool.llvm.archiver.base.2054931917" name="LLVM archiver" superClass="cdt.managedbuild.tool.llvm.archiver.base"/>
+                                                       <tool id="cdt.managedbuild.tool.llvm.c.compiler.base.1957805273" name="LLVM Clang" superClass="cdt.managedbuild.tool.llvm.c.compiler.base">
+                                                               <inputType id="cdt.managedbuild.tool.llvm.c.compiler.input.342575696" superClass="cdt.managedbuild.tool.llvm.c.compiler.input"/>
+                                                       </tool>
+                                                       <tool id="cdt.managedbuild.tool.llvm.cpp.compiler.base.293492776" name="LLVM Clang++" superClass="cdt.managedbuild.tool.llvm.cpp.compiler.base">
+                                                               <inputType id="cdt.managedbuild.tool.llvm.cpp.compiler.input.2068687017" superClass="cdt.managedbuild.tool.llvm.cpp.compiler.input"/>
+                                                       </tool>
+                                                       <tool id="cdt.managedbuild.tool.llvm.c.linker.base.1892819112" name="LLVM Clang C linker" superClass="cdt.managedbuild.tool.llvm.c.linker.base"/>
+                                                       <tool id="cdt.managedbuild.tool.llvm.cpp.linker.base.1107548053" name="LLVM Clang C++ linker" superClass="cdt.managedbuild.tool.llvm.cpp.linker.base">
+                                                               <option id="llvm.c.link.option.libs.1380313880" name="Libraries (-l)" superClass="llvm.c.link.option.libs" valueType="libs">
+                                                                       <listOptionValue builtIn="false" value="stdc++"/>
+                                                               </option>
+                                                               <option id="llvm.c.link.option.paths.726789935" name="Library search path (-L)" superClass="llvm.c.link.option.paths" valueType="libPaths">
+                                                                       <listOptionValue builtIn="false" value="/usr/lib/gcc/x86_64-w64-mingw32/5.3-win32/"/>
+                                                               </option>
+                                                               <inputType id="cdt.managedbuild.tool.llvm.c.linker.input.1805560748" superClass="cdt.managedbuild.tool.llvm.c.linker.input">
+                                                                       <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+                                                                       <additionalInput kind="additionalinput" paths="$(LIBS)"/>
+                                                               </inputType>
+                                                       </tool>
+                                               </toolChain>
+                                       </folderInfo>
+                               </configuration>
+                       </storageModule>
+                       <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+               </cconfiguration>
+       </storageModule>
+       <storageModule moduleId="scannerConfiguration">
+               <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+               <scannerConfigBuildInfo instanceId="0.1265155043">
+                       <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+               </scannerConfigBuildInfo>
+       </storageModule>
+       <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+               <project id="build.null.28162506" name="build"/>
+       </storageModule>
+       <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
+       <storageModule moduleId="refreshScope" versionNumber="2">
+               <configuration configurationName="Default">
+                       <resource resourceType="PROJECT" workspacePath="/build"/>
+               </configuration>
+       </storageModule>
+       <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+</cproject>
diff --git a/build/.project b/build/.project
new file mode 100644 (file)
index 0000000..d44d09a
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>build</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+                       <triggers>clean,full,incremental,</triggers>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+                       <triggers>full,incremental,</triggers>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.cdt.core.cnature</nature>
+               <nature>org.eclipse.cdt.core.ccnature</nature>
+               <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+               <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+       </natures>
+       <linkedResources>
+               <link>
+                       <name>.clang-format</name>
+                       <type>1</type>
+                       <locationURI>WORKSPACE_LOC/.clang-format</locationURI>
+               </link>
+               <link>
+                       <name>.gitignore</name>
+                       <type>1</type>
+                       <locationURI>WORKSPACE_LOC/.gitignore</locationURI>
+               </link>
+               <link>
+                       <name>CMakeLists.txt</name>
+                       <type>1</type>
+                       <locationURI>WORKSPACE_LOC/CMakeLists.txt</locationURI>
+               </link>
+               <link>
+                       <name>source</name>
+                       <type>2</type>
+                       <locationURI>WORKSPACE_LOC/src</locationURI>
+               </link>
+               <link>
+                       <name>test-files</name>
+                       <type>2</type>
+                       <locationURI>WORKSPACE_LOC/test-files</locationURI>
+               </link>
+       </linkedResources>
+</projectDescription>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..23627cc
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright 2017 Jacob Lifshay
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+add_subdirectory(spirv)
+add_subdirectory(demo)
+add_subdirectory(util)
\ No newline at end of file
diff --git a/src/demo/CMakeLists.txt b/src/demo/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f13abf1
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright 2017 Jacob Lifshay
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+set(sources demo.cpp) 
+add_executable(demo ${sources})
+target_link_libraries(demo spirv util)
diff --git a/src/demo/demo.cpp b/src/demo/demo.cpp
new file mode 100644 (file)
index 0000000..65ebb11
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <array>
+#include <type_traits>
+#include <string>
+#include "../spirv/spirv.h"
+#include "../util/optional.h"
+
+namespace vulkan_cpu
+{
+namespace test
+{
+util::optional<std::vector<spirv::word>> load_file(const char *fileName)
+{
+    using spirv::word;
+    constexpr int eof = std::char_traits<char>::eof();
+    std::ifstream is;
+    is.open(fileName, std::ios::in | std::ios::binary);
+    if(!is)
+        return {};
+    constexpr std::size_t block_size = 0x1000;
+    std::vector<std::array<word, block_size>> blocks;
+    std::array<unsigned char, sizeof(word)> word_bytes{};
+    static_assert(sizeof(word) == 4, "");
+    static_assert(std::is_same<std::uint8_t, unsigned char>::value, "");
+    auto read_little_endian = [](const unsigned char *bytes) -> word
+    {
+        word retval = bytes[3];
+        retval <<= 8;
+        retval |= bytes[2];
+        retval <<= 8;
+        retval |= bytes[1];
+        retval <<= 8;
+        retval |= bytes[0];
+        return retval;
+    };
+    auto read_big_endian = [](const unsigned char *bytes) -> word
+    {
+        word retval = bytes[0];
+        retval <<= 8;
+        retval |= bytes[1];
+        retval <<= 8;
+        retval |= bytes[2];
+        retval <<= 8;
+        retval |= bytes[3];
+        return retval;
+    };
+    for(unsigned char &byte : word_bytes)
+    {
+        auto v = is.get();
+        if(v == eof)
+            return {};
+        byte = v;
+    }
+    word (*read_word_fn)(const unsigned char *) = nullptr;
+    if(read_little_endian(word_bytes.data()) == spirv::magic_number)
+        read_word_fn = read_little_endian;
+    else if(read_big_endian(word_bytes.data()) == spirv::magic_number)
+        read_word_fn = read_big_endian;
+    else
+        return {};
+    std::size_t word_count = 1;
+    blocks.emplace_back();
+    blocks[0][0] = read_word_fn(word_bytes.data());
+    std::size_t word_in_block_index = 1;
+    while(is.peek() != eof)
+    {
+        for(unsigned char &byte : word_bytes)
+        {
+            auto v = is.get();
+            if(v == eof)
+                return {};
+            byte = v;
+        }
+        blocks.back()[word_in_block_index++] = read_word_fn(word_bytes.data());
+        word_count++;
+        if(word_in_block_index >= block_size)
+        {
+            word_in_block_index = 0;
+            blocks.emplace_back();
+        }
+    }
+    std::vector<word> retval;
+    retval.reserve(word_count);
+    word_in_block_index = 0;
+    for(std::size_t word_index = 0, block_index = 0; word_index < word_count; word_index++)
+    {
+        retval.push_back(blocks[block_index][word_in_block_index++]);
+        if(word_in_block_index >= block_size)
+        {
+            word_in_block_index = 0;
+            block_index++;
+        }
+    }
+    return std::move(retval);
+}
+
+void dump_words(const spirv::word *words, std::size_t word_count)
+{
+    constexpr std::size_t max_words_per_line = 4;
+    auto old_fill = std::cout.fill('0');
+    auto old_flags = std::cout.flags(std::ios::uppercase | std::ios::hex | std::ios::right);
+    auto old_width = std::cout.width();
+    bool wrote_line_beginning = false;
+    bool wrote_line_ending = true;
+    std::cout << "Words:\n";
+    std::size_t current_words_per_line = 0;
+    std::size_t index;
+    auto seperator = "";
+    auto write_line_beginning = [&]()
+    {
+        std::cout.width(8);
+        std::cout << index << ":";
+        seperator = " ";
+        wrote_line_beginning = true;
+        wrote_line_ending = false;
+    };
+    std::string chars = "";
+    auto write_line_ending = [&]()
+    {
+       while(current_words_per_line < max_words_per_line)
+       {
+            std::cout << seperator;
+            seperator = " ";
+            std::cout.width(8);
+            std::cout.fill(' ');
+            std::cout << "";
+            std::cout.fill('0');
+            current_words_per_line++;
+       }
+       std::cout << seperator << " |" << chars << "|\n";
+        seperator = "";
+        wrote_line_ending = true;
+        wrote_line_beginning = false;
+        current_words_per_line = 0;
+        chars.clear();
+    };
+    auto append_char = [&](unsigned ch)
+    {
+       if(ch >= 0x20U && ch < 0x7FU)
+               chars += static_cast<char>(ch);
+       else
+               chars += '.';
+    };
+    auto write_word = [&](spirv::word w)
+    {
+        std::cout << seperator;
+        seperator = " ";
+        std::cout.width(8);
+        std::cout << w;
+        current_words_per_line++;
+        append_char(w & 0xFFU);
+        append_char((w >> 8) & 0xFFU);
+        append_char((w >> 16) & 0xFFU);
+        append_char((w >> 24) & 0xFFU);
+    };
+    for(index = 0; index < word_count; index++)
+    {
+        if(current_words_per_line >= max_words_per_line)
+            write_line_ending();
+        if(!wrote_line_beginning)
+            write_line_beginning();
+        write_word(words[index]);
+    }
+    if(!wrote_line_ending)
+        write_line_ending();
+    std::cout.flush();
+    std::cout.width(old_width);
+    std::cout.fill(old_fill);
+    std::cout.flags(old_flags);
+}
+
+void dump_words(const std::vector<spirv::word> &words)
+{
+    dump_words(words.data(), words.size());
+}
+
+int test_main(int argc, char **argv)
+{
+    auto file = load_file("test-files/test.spv");
+    if(file)
+        dump_words(*file);
+    return 0;
+}
+}
+}
+
+int main(int argc, char **argv)
+{
+    return vulkan_cpu::test::test_main(argc, argv);
+    using namespace vulkan_cpu;
+}
diff --git a/src/spirv/CMakeLists.txt b/src/spirv/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c470ba2
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright 2017 Jacob Lifshay
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+set(sources spirv.cpp) 
+add_library(spirv STATIC ${sources})
\ No newline at end of file
diff --git a/src/spirv/spirv.cpp b/src/spirv/spirv.cpp
new file mode 100644 (file)
index 0000000..1abdc51
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include "spirv.h"
diff --git a/src/spirv/spirv.h b/src/spirv/spirv.h
new file mode 100644 (file)
index 0000000..5e564c2
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef SPIRV_SPIRV_H_
+#define SPIRV_SPIRV_H_
+
+#include <cstdint>
+
+namespace vulkan_cpu
+{
+namespace spirv
+{
+typedef std::uint32_t word;
+constexpr word magic_number = 0x07230203UL;
+}
+}
+
+#endif /* SPIRV_SPIRV_H_ */
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
new file mode 100644 (file)
index 0000000..854e345
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright 2017 Jacob Lifshay
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+set(sources in_place.cpp
+            is_referenceable.cpp
+            is_swappable.cpp
+            optional.cpp)
+add_library(util STATIC ${sources})
diff --git a/src/util/in_place.cpp b/src/util/in_place.cpp
new file mode 100644 (file)
index 0000000..76092e1
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include "in_place.h"
diff --git a/src/util/in_place.h b/src/util/in_place.h
new file mode 100644 (file)
index 0000000..d95ca1b
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef UTIL_IN_PLACE_H_
+#define UTIL_IN_PLACE_H_
+
+#include <cstddef>
+
+namespace vulkan_cpu
+{
+namespace util
+{
+struct in_place_t
+{
+    explicit in_place_t() = default;
+};
+
+constexpr in_place_t in_place{};
+
+template <typename T>
+struct in_place_type_t
+{
+    explicit in_place_type_t() = default;
+};
+
+template <typename T>
+constexpr in_place_type_t<T> in_place_type{};
+
+template <std::size_t I>
+struct in_place_index_t
+{
+    explicit in_place_index_t() = default;
+};
+
+template <std::size_t I>
+constexpr in_place_index_t<I> in_place_index{};
+}
+}
+
+#endif /* UTIL_IN_PLACE_H_ */
diff --git a/src/util/is_referenceable.cpp b/src/util/is_referenceable.cpp
new file mode 100644 (file)
index 0000000..bff1e22
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include "is_referenceable.h"
diff --git a/src/util/is_referenceable.h b/src/util/is_referenceable.h
new file mode 100644 (file)
index 0000000..9b0c0ea
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef UTIL_IS_REFERENCEABLE_H_
+#define UTIL_IS_REFERENCEABLE_H_
+
+#include <type_traits>
+
+namespace vulkan_cpu
+{
+namespace util
+{
+template <typename T>
+struct is_referenceable
+    : public std::integral_constant<bool, std::is_object<T>::value || std::is_reference<T>::value>
+{
+};
+
+template <typename Return_Type, typename... Types>
+struct is_referenceable<Return_Type(Types...)> : public std::true_type
+{
+};
+
+template <typename Return_Type, typename... Types>
+struct is_referenceable<Return_Type(Types..., ...)> : public std::true_type
+{
+};
+}
+}
+
+#endif /* UTIL_IS_REFERENCEABLE_H_ */
diff --git a/src/util/is_swappable.cpp b/src/util/is_swappable.cpp
new file mode 100644 (file)
index 0000000..51ca86c
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include "is_swappable.h"
diff --git a/src/util/is_swappable.h b/src/util/is_swappable.h
new file mode 100644 (file)
index 0000000..b744200
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef UTIL_IS_SWAPPABLE_H_
+#define UTIL_IS_SWAPPABLE_H_
+
+#include <utility>
+#include <type_traits>
+#include "is_referenceable.h"
+
+namespace vulkan_cpu_util_is_swappable_unrelated_namespace
+{
+using std::swap;
+template <typename T, typename U, bool Is_Void = std::is_void<T>::value || std::is_void<T>::value>
+class is_swappable_with
+{
+private:
+    template <typename L,
+              typename R,
+              typename = decltype(swap(std::declval<L>(), std::declval<R>()))>
+    static void fn(int);
+    template <typename L, typename R>
+    static char fn(...);
+
+public:
+    static constexpr bool value =
+        std::is_void<decltype(fn<T, U>(0))>::value && std::is_void<decltype(fn<U, T>(0))>::value;
+};
+
+template <typename T, typename U>
+class is_swappable_with<T, U, true>
+{
+public:
+    static constexpr bool value = false;
+};
+
+template <typename T, typename U, bool Is_Swappable_With = is_swappable_with<T, U>::value>
+struct is_nothrow_swappable_with
+{
+    static constexpr bool value = noexcept(swap(std::declval<T>(), std::declval<U>()))
+                                  && noexcept(swap(std::declval<U>(), std::declval<T>()));
+};
+
+template <typename T, typename U>
+struct is_nothrow_swappable_with<T, U, false>
+{
+    static constexpr bool value = false;
+};
+}
+
+namespace vulkan_cpu
+{
+namespace util
+{
+template <typename T, typename U>
+struct is_swappable_with
+    : public std::integral_constant<bool,
+                                    vulkan_cpu_util_is_swappable_unrelated_namespace::
+                                        is_swappable_with<T, U>::value>
+{
+};
+
+template <typename T, typename U>
+struct is_nothrow_swappable_with
+    : public std::integral_constant<bool,
+                                    vulkan_cpu_util_is_swappable_unrelated_namespace::
+                                        is_nothrow_swappable_with<T, U>::value>
+{
+};
+
+namespace detail
+{
+template <typename T, bool Is_Referenceable = is_referenceable<T>::value>
+struct is_swappable_helper
+{
+    static constexpr bool value = is_swappable_with<T &, T &>::value;
+};
+
+template <typename T>
+struct is_swappable_helper<T, false>
+{
+    static constexpr bool value = false;
+};
+
+template <typename T, bool Is_Referenceable = is_referenceable<T>::value>
+struct is_nothrow_swappable_helper
+{
+    static constexpr bool value = is_nothrow_swappable_with<T &, T &>::value;
+};
+
+template <typename T>
+struct is_nothrow_swappable_helper<T, false>
+{
+    static constexpr bool value = false;
+};
+}
+
+template <typename T>
+struct is_swappable : public std::integral_constant<bool, detail::is_swappable_helper<T>::value>
+{
+};
+
+template <typename T>
+struct is_nothrow_swappable
+    : public std::integral_constant<bool, detail::is_nothrow_swappable_helper<T>::value>
+{
+};
+}
+}
+
+#endif /* UTIL_IS_SWAPPABLE_H_ */
diff --git a/src/util/optional.cpp b/src/util/optional.cpp
new file mode 100644 (file)
index 0000000..bfccd96
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include "optional.h"
diff --git a/src/util/optional.h b/src/util/optional.h
new file mode 100644 (file)
index 0000000..699d700
--- /dev/null
@@ -0,0 +1,913 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef UTIL_OPTIONAL_H_
+#define UTIL_OPTIONAL_H_
+
+#include <type_traits>
+#include <new>
+#include <memory>
+#include <initializer_list>
+#include <utility>
+#include <cassert>
+#include <exception>
+#include <functional>
+#include "in_place.h"
+#include "is_swappable.h"
+
+namespace vulkan_cpu
+{
+namespace util
+{
+struct nullopt_t
+{
+    constexpr explicit nullopt_t(int)
+    {
+    }
+};
+
+constexpr nullopt_t nullopt(0);
+
+class bad_optional_access : public std::exception
+{
+public:
+    virtual const char *what() const noexcept override
+    {
+        return "bad_optional_access";
+    }
+};
+
+namespace detail
+{
+template <typename T,
+          bool Is_Trivially_Destructible = std::is_trivially_destructible<T>::value,
+          bool Is_Trivially_Copyable = std::is_trivially_copyable<T>::value>
+struct optional_base
+{
+    union
+    {
+        T full_value;
+        alignas(T) char empty_value[sizeof(T)];
+    };
+    bool is_full;
+    constexpr optional_base() noexcept : empty_value{}, is_full(false)
+    {
+    }
+    constexpr optional_base(nullopt_t) noexcept : empty_value{}, is_full(false)
+    {
+    }
+    void reset() noexcept
+    {
+        if(is_full)
+            full_value.~T();
+    }
+    template <typename... Types>
+    T &emplace(Types &&... args) noexcept(std::is_nothrow_constructible<T, Types...>::value)
+    {
+        reset();
+        ::new(static_cast<void *>(std::addressof(full_value))) T(std::forward<Types>(args)...);
+        is_full = true;
+        return full_value;
+    }
+    template <
+        typename U,
+        typename... Types,
+        typename = typename std::
+            enable_if<std::is_constructible<T, std::initializer_list<U>, Types...>::value>::type>
+    T &emplace(std::initializer_list<U> init_list, Types &&... args) noexcept(
+        std::is_nothrow_constructible<T, std::initializer_list<U>, Types...>::value)
+    {
+        reset();
+        ::new(static_cast<void *>(std::addressof(full_value)))
+            T(init_list, std::forward<Types>(args)...);
+        is_full = true;
+        return full_value;
+    }
+    optional_base(const optional_base &rt) noexcept(std::is_nothrow_copy_constructible<T>::value)
+        : empty_value{}, is_full(false)
+    {
+        if(rt.is_full)
+            emplace(rt.full_value);
+    }
+    optional_base(optional_base &&rt) noexcept(std::is_nothrow_move_constructible<T>::value)
+        : empty_value{}, is_full(false)
+    {
+        if(rt.is_full)
+            emplace(std::move(rt.full_value));
+    }
+    template <typename... Types,
+              typename = typename std::enable_if<std::is_constructible<T, Types...>::value>::type>
+    constexpr explicit optional_base(in_place_t, Types &&... args) noexcept(
+        std::is_nothrow_constructible<T, Types...>::value)
+        : full_value(std::forward<Types>(args)...), is_full(true)
+    {
+    }
+    template <
+        typename U,
+        typename... Types,
+        typename = typename std::
+            enable_if<std::is_constructible<T, std::initializer_list<U>, Types...>::value>::type>
+    constexpr explicit optional_base(
+        in_place_t,
+        std::initializer_list<U> init_list,
+        Types &&... args) noexcept(std::is_nothrow_constructible<T, Types...>::value)
+        : full_value(init_list, std::forward<Types>(args)...), is_full(true)
+    {
+    }
+    ~optional_base()
+    {
+        reset();
+    }
+    optional_base &operator=(const optional_base &rt) noexcept(
+        std::is_nothrow_copy_assignable<T>::value)
+    {
+        if(!rt.is_full)
+            reset();
+        else if(!is_full)
+            emplace(rt.full_value);
+        else
+            full_value = rt.full_value;
+        return *this;
+    }
+    optional_base &operator=(optional_base &&rt) noexcept(std::is_nothrow_move_assignable<T>::value)
+    {
+        if(!rt.is_full)
+            reset();
+        else if(!is_full)
+            emplace(std::move(rt.full_value));
+        else
+            full_value = std::move(rt.full_value);
+        return *this;
+    }
+};
+
+template <typename T>
+struct optional_base<T, true, false>
+{
+    union
+    {
+        T full_value;
+        alignas(T) char empty_value[sizeof(T)];
+    };
+    bool is_full;
+    constexpr optional_base() noexcept : empty_value{}, is_full(false)
+    {
+    }
+    constexpr optional_base(nullopt_t) noexcept : empty_value{}, is_full(false)
+    {
+    }
+    void reset() noexcept
+    {
+        // full_value.~T() not needed
+    }
+    template <typename... Types>
+    T &emplace(Types &&... args) noexcept(std::is_nothrow_constructible<T, Types...>::value)
+    {
+        reset();
+        ::new(static_cast<void *>(std::addressof(full_value))) T(std::forward<Types>(args)...);
+        is_full = true;
+        return full_value;
+    }
+    template <
+        typename U,
+        typename... Types,
+        typename = typename std::
+            enable_if<std::is_constructible<T, std::initializer_list<U>, Types...>::value>::type>
+    T &emplace(std::initializer_list<U> init_list, Types &&... args) noexcept(
+        std::is_nothrow_constructible<T, std::initializer_list<U>, Types...>::value)
+    {
+        reset();
+        ::new(static_cast<void *>(std::addressof(full_value)))
+            T(init_list, std::forward<Types>(args)...);
+        is_full = true;
+        return full_value;
+    }
+    optional_base(const optional_base &rt) noexcept(std::is_nothrow_copy_constructible<T>::value)
+        : empty_value{}, is_full(false)
+    {
+        if(rt.is_full)
+            emplace(rt.full_value);
+    }
+    optional_base(optional_base &&rt) noexcept(std::is_nothrow_move_constructible<T>::value)
+        : empty_value{}, is_full(false)
+    {
+        if(rt.is_full)
+            emplace(std::move(rt.full_value));
+    }
+    template <typename... Types,
+              typename = typename std::enable_if<std::is_constructible<T, Types...>::value>::type>
+    constexpr explicit optional_base(in_place_t, Types &&... args) noexcept(
+        std::is_nothrow_constructible<T, Types...>::value)
+        : full_value(std::forward<Types>(args)...), is_full(true)
+    {
+    }
+    template <
+        typename U,
+        typename... Types,
+        typename = typename std::
+            enable_if<std::is_constructible<T, std::initializer_list<U>, Types...>::value>::type>
+    constexpr explicit optional_base(
+        in_place_t,
+        std::initializer_list<U> init_list,
+        Types &&... args) noexcept(std::is_nothrow_constructible<T, Types...>::value)
+        : full_value(init_list, std::forward<Types>(args)...), is_full(true)
+    {
+    }
+    ~optional_base() = default;
+    optional_base &operator=(const optional_base &rt) noexcept(
+        std::is_nothrow_copy_assignable<T>::value)
+    {
+        if(!rt.is_full)
+            reset();
+        else if(!is_full)
+            emplace(rt.full_value);
+        else
+            full_value = rt.full_value;
+        return *this;
+    }
+    optional_base &operator=(optional_base &&rt) noexcept(std::is_nothrow_move_assignable<T>::value)
+    {
+        if(!rt.is_full)
+            reset();
+        else if(!is_full)
+            emplace(std::move(rt.full_value));
+        else
+            full_value = std::move(rt.full_value);
+        return *this;
+    }
+};
+
+template <typename T>
+struct optional_base<T, true, true>
+{
+    union
+    {
+        T full_value;
+        alignas(T) char empty_value[sizeof(T)];
+    };
+    bool is_full;
+    constexpr optional_base() noexcept : empty_value{}, is_full(false)
+    {
+    }
+    constexpr optional_base(nullopt_t) noexcept : empty_value{}, is_full(false)
+    {
+    }
+    void reset() noexcept
+    {
+        // full_value.~T() not needed
+    }
+    template <typename... Types>
+    T &emplace(Types &&... args) noexcept(std::is_nothrow_constructible<T, Types...>::value)
+    {
+        reset();
+        ::new(static_cast<void *>(std::addressof(full_value))) T(std::forward<Types>(args)...);
+        is_full = true;
+        return full_value;
+    }
+    template <
+        typename U,
+        typename... Types,
+        typename = typename std::
+            enable_if<std::is_constructible<T, std::initializer_list<U>, Types...>::value>::type>
+    T &emplace(std::initializer_list<U> init_list, Types &&... args) noexcept(
+        std::is_nothrow_constructible<T, std::initializer_list<U>, Types...>::value)
+    {
+        reset();
+        ::new(static_cast<void *>(std::addressof(full_value)))
+            T(init_list, std::forward<Types>(args)...);
+        is_full = true;
+        return full_value;
+    }
+    constexpr optional_base(const optional_base &rt) noexcept = default;
+    constexpr optional_base(optional_base &&rt) noexcept = default;
+    template <typename... Types,
+              typename = typename std::enable_if<std::is_constructible<T, Types...>::value>::type>
+    constexpr explicit optional_base(in_place_t, Types &&... args) noexcept(
+        std::is_nothrow_constructible<T, Types...>::value)
+        : full_value(std::forward<Types>(args)...), is_full(true)
+    {
+    }
+    template <
+        typename U,
+        typename... Types,
+        typename = typename std::
+            enable_if<std::is_constructible<T, std::initializer_list<U>, Types...>::value>::type>
+    constexpr explicit optional_base(
+        in_place_t,
+        std::initializer_list<U> init_list,
+        Types &&... args) noexcept(std::is_nothrow_constructible<T, Types...>::value)
+        : full_value(init_list, std::forward<Types>(args)...), is_full(true)
+    {
+    }
+    ~optional_base() = default;
+    optional_base &operator=(const optional_base &rt) noexcept = default;
+    optional_base &operator=(optional_base &&rt) noexcept = default;
+};
+}
+
+template <typename T>
+class optional;
+
+namespace detail
+{
+template <typename T, typename U, typename U_Ref>
+constexpr bool optional_needs_conversion_constructors() noexcept
+{
+    if(!std::is_constructible<T, U_Ref>::value)
+        return false;
+    if(std::is_constructible<T, optional<U> &>::value)
+        return false;
+    if(std::is_constructible<T, const optional<U> &>::value)
+        return false;
+    if(std::is_constructible<T, optional<U> &&>::value)
+        return false;
+    if(std::is_constructible<T, const optional<U> &&>::value)
+        return false;
+    if(std::is_convertible<optional<U> &, T>::value)
+        return false;
+    if(std::is_convertible<const optional<U> &, T>::value)
+        return false;
+    if(std::is_convertible<optional<U> &&, T>::value)
+        return false;
+    if(std::is_convertible<const optional<U> &&, T>::value)
+        return false;
+    return true;
+}
+
+template <typename T, typename U, typename U_Ref>
+constexpr bool optional_needs_conversion_from_optional_assign_operators() noexcept
+{
+    if(!std::is_constructible<T, U_Ref>::value)
+        return false;
+    if(!std::is_assignable<T &, U_Ref>::value)
+        return false;
+    if(std::is_constructible<T, optional<U> &>::value)
+        return false;
+    if(std::is_constructible<T, const optional<U> &>::value)
+        return false;
+    if(std::is_constructible<T, optional<U> &&>::value)
+        return false;
+    if(std::is_constructible<T, const optional<U> &&>::value)
+        return false;
+    if(std::is_convertible<optional<U> &, T>::value)
+        return false;
+    if(std::is_convertible<const optional<U> &, T>::value)
+        return false;
+    if(std::is_convertible<optional<U> &&, T>::value)
+        return false;
+    if(std::is_convertible<const optional<U> &&, T>::value)
+        return false;
+    if(std::is_assignable<T &, optional<U> &>::value)
+        return false;
+    if(std::is_assignable<T &, const optional<U> &>::value)
+        return false;
+    if(std::is_assignable<T &, optional<U> &&>::value)
+        return false;
+    if(std::is_assignable<T &, const optional<U> &&>::value)
+        return false;
+    return true;
+}
+}
+
+template <typename T>
+class optional : private detail::optional_base<T>
+{
+private:
+    typedef detail::optional_base<T> base;
+    using base::is_full;
+    using base::full_value;
+
+public:
+    using base::base;
+    using base::operator=;
+    using base::reset;
+    constexpr optional() noexcept = default;
+    template <typename U,
+              typename = typename std::
+                  enable_if<detail::optional_needs_conversion_constructors<T, U, const U &>()
+                            && std::is_convertible<const U &, T>::value>::type>
+    optional(const optional<U> &rt) noexcept(std::is_nothrow_constructible<T, const U &>::value)
+        : base()
+    {
+        if(rt)
+            emplace(*rt);
+    }
+    template <typename U,
+              typename = typename std::
+                  enable_if<detail::optional_needs_conversion_constructors<T, U, const U &>()
+                            && !std::is_convertible<const U &, T>::value>::type,
+              typename = void>
+    explicit optional(const optional<U> &rt) noexcept(
+        std::is_nothrow_constructible<T, const U &>::value)
+        : base()
+    {
+        if(rt)
+            emplace(*rt);
+    }
+    template <
+        typename U,
+        typename =
+            typename std::enable_if<detail::optional_needs_conversion_constructors<T, U, U &&>()
+                                    && std::is_convertible<U &&, T>::value>::type>
+    optional(optional<U> &&rt) noexcept(std::is_nothrow_constructible<T, U &&>::value)
+        : base()
+    {
+        if(rt)
+            emplace(std::move(*rt));
+    }
+    template <
+        typename U,
+        typename =
+            typename std::enable_if<detail::optional_needs_conversion_constructors<T, U, U &&>()
+                                    && !std::is_convertible<U &&, T>::value>::type,
+        typename = void>
+    explicit optional(optional<U> &&rt) noexcept(std::is_nothrow_constructible<T, U &&>::value)
+        : base()
+    {
+        if(rt)
+            emplace(std::move(*rt));
+    }
+    template <typename U,
+              typename = typename std::
+                  enable_if<std::is_constructible<T, U &&>::value
+                            && !std::is_same<typename std::decay<U>::type, in_place_t>::value
+                            && !std::is_same<typename std::decay<U>::type, optional>::value
+                            && std::is_convertible<U &&, T>::value>::type,
+              typename = void>
+    constexpr optional(U &&value) noexcept(std::is_nothrow_constructible<T, U &&>::value)
+        : base(in_place, std::forward<U>(value))
+    {
+    }
+    template <typename U,
+              typename = typename std::
+                  enable_if<std::is_constructible<T, U &&>::value
+                            && !std::is_same<typename std::decay<U>::type, in_place_t>::value
+                            && !std::is_same<typename std::decay<U>::type, optional>::value
+                            && !std::is_convertible<U &&, T>::value>::type>
+    explicit constexpr optional(U &&value) noexcept(std::is_nothrow_constructible<T, U &&>::value)
+        : base(in_place, std::forward<U>(value))
+    {
+    }
+    template <typename U = T,
+              typename = typename std::
+                  enable_if<!std::is_same<typename std::decay<U>::type, optional>::value
+                            && std::is_constructible<T, U>::value
+                            && std::is_assignable<T &, U>::value
+                            && (!std::is_scalar<T>::value
+                                || !std::is_same<typename std::decay<U>::type, T>::value)>::type>
+    optional &operator=(U &&value) noexcept(std::is_nothrow_constructible<T, U &&>::value
+                                                &&std::is_nothrow_assignable<T &, U &&>::value)
+    {
+        if(is_full)
+            full_value = std::forward<U>(value);
+        else
+            emplace(std::forward<U>(value));
+        return *this;
+    }
+    optional &operator=(nullopt_t) noexcept
+    {
+        reset();
+        return *this;
+    }
+    template <
+        typename U,
+        typename = typename std::enable_if< //
+            detail::optional_needs_conversion_from_optional_assign_operators<T, U, const U &>()>::
+            type>
+    optional &operator=(const optional<U> &rt) noexcept(
+        std::is_nothrow_constructible<T, const U &>::value
+            &&std::is_nothrow_assignable<T &, const U &>::value)
+    {
+        if(!rt)
+            reset();
+        else if(!is_full)
+            emplace(*rt);
+        else
+            full_value = *rt;
+        return *this;
+    }
+    template <
+        typename U,
+        typename = typename std::enable_if< //
+            detail::optional_needs_conversion_from_optional_assign_operators<T, U, U &&>()>::type>
+    optional &operator=(optional<U> &&rt) noexcept(std::is_nothrow_constructible<T, U &&>::value &&
+                                                       std::is_nothrow_assignable<T &, U &&>::value)
+    {
+        if(!rt)
+            reset();
+        else if(!is_full)
+            emplace(std::move(*rt));
+        else
+            full_value = std::move(*rt);
+        return *this;
+    }
+    constexpr const T *operator->() const noexcept
+    {
+        assert(is_full);
+        return std::addressof(full_value);
+    }
+    constexpr T *operator->() noexcept
+    {
+        assert(is_full);
+        return std::addressof(full_value);
+    }
+    constexpr const T &operator*() const &noexcept
+    {
+        assert(is_full);
+        return full_value;
+    }
+    constexpr T &operator*() & noexcept
+    {
+        assert(is_full);
+        return full_value;
+    }
+    constexpr const T &&operator*() const &&noexcept
+    {
+        assert(is_full);
+        return std::move(full_value);
+    }
+    constexpr T &&operator*() && noexcept
+    {
+        assert(is_full);
+        return std::move(full_value);
+    }
+    constexpr explicit operator bool() const noexcept
+    {
+        return is_full;
+    }
+    constexpr bool has_value() const noexcept
+    {
+        return is_full;
+    }
+    constexpr T &value() &
+    {
+        if(!is_full)
+            throw bad_optional_access();
+        return full_value;
+    }
+    constexpr const T &value() const &
+    {
+        if(!is_full)
+            throw bad_optional_access();
+        return full_value;
+    }
+    constexpr T &&value() &&
+    {
+        if(!is_full)
+            throw bad_optional_access();
+        return std::move(full_value);
+    }
+    constexpr const T &&value() const &&
+    {
+        if(!is_full)
+            throw bad_optional_access();
+        return std::move(full_value);
+    }
+    template <typename U>
+    constexpr T value_or(U &&default_value) const &noexcept(
+        std::is_nothrow_copy_constructible<T>::value //
+            &&noexcept(static_cast<T>(std::declval<U>())))
+    {
+        return is_full ? full_value : static_cast<T>(std::forward<U>(default_value));
+    }
+    template <typename U>
+        constexpr T value_or(U &&default_value)
+        && noexcept(std::is_nothrow_copy_constructible<T>::value //
+                        &&noexcept(static_cast<T>(std::declval<U>())))
+    {
+        return is_full ? std::move(full_value) : static_cast<T>(std::forward<U>(default_value));
+    }
+    void swap(optional &other) noexcept(
+        std::is_nothrow_move_constructible<T>::value &&util::is_nothrow_swappable<T>::value)
+    {
+        if(is_full)
+        {
+            if(other.is_full)
+            {
+                using std::swap;
+                swap(full_value, other.full_value);
+            }
+            else
+            {
+                other.emplace(std::move(full_value));
+                reset();
+            }
+        }
+        else if(other.is_full)
+        {
+            emplace(std::move(other.full_value));
+            other.reset();
+        }
+    }
+};
+
+template <typename T, typename U>
+constexpr bool operator==(const optional<T> &l, const optional<T> &r) noexcept(noexcept(*l == *r))
+{
+    if(!l.has_value() || !r.has_value())
+        return !r.has_value();
+    return *l == *r;
+}
+
+template <typename T, typename U>
+constexpr bool operator!=(const optional<T> &l, const optional<T> &r) noexcept(noexcept(*l == *r))
+{
+    if(!l.has_value() || !r.has_value())
+        return r.has_value();
+    return *l != *r;
+}
+
+template <typename T, typename U>
+constexpr bool operator<(const optional<T> &l, const optional<T> &r) noexcept(noexcept(*l == *r))
+{
+    if(!l.has_value() || !r.has_value())
+        return r.has_value();
+    return *l < *r;
+}
+
+template <typename T, typename U>
+constexpr bool operator>(const optional<T> &l, const optional<T> &r) noexcept(noexcept(*l == *r))
+{
+    if(!l.has_value() || !r.has_value())
+        return l.has_value();
+    return *l > *r;
+}
+
+template <typename T, typename U>
+constexpr bool operator<=(const optional<T> &l, const optional<T> &r) noexcept(noexcept(*l == *r))
+{
+    if(!l.has_value() || !r.has_value())
+        return !l.has_value();
+    return *l <= *r;
+}
+
+template <typename T, typename U>
+constexpr bool operator>=(const optional<T> &l, const optional<T> &r) noexcept(noexcept(*l == *r))
+{
+    if(!l.has_value() || !r.has_value())
+        return !r.has_value();
+    return *l >= *r;
+}
+
+template <typename T>
+constexpr bool operator==(const optional<T> &v, nullopt_t) noexcept
+{
+    return !v.has_value();
+}
+
+template <typename T>
+constexpr bool operator!=(const optional<T> &v, nullopt_t) noexcept
+{
+    return v.has_value();
+}
+
+template <typename T>
+constexpr bool operator<(const optional<T> &v, nullopt_t) noexcept
+{
+    return false;
+}
+
+template <typename T>
+constexpr bool operator>(const optional<T> &v, nullopt_t) noexcept
+{
+    return v.has_value();
+}
+
+template <typename T>
+constexpr bool operator<=(const optional<T> &v, nullopt_t) noexcept
+{
+    return !v.has_value();
+}
+
+template <typename T>
+constexpr bool operator>=(const optional<T> &v, nullopt_t) noexcept
+{
+    return true;
+}
+
+template <typename T>
+constexpr bool operator==(nullopt_t, const optional<T> &v) noexcept
+{
+    return !v.has_value();
+}
+
+template <typename T>
+constexpr bool operator!=(nullopt_t, const optional<T> &v) noexcept
+{
+    return v.has_value();
+}
+
+template <typename T>
+constexpr bool operator<(nullopt_t, const optional<T> &v) noexcept
+{
+    return v.has_value();
+}
+
+template <typename T>
+constexpr bool operator>(nullopt_t, const optional<T> &v) noexcept
+{
+    return false;
+}
+
+template <typename T>
+constexpr bool operator<=(nullopt_t, const optional<T> &v) noexcept
+{
+    return true;
+}
+
+template <typename T>
+constexpr bool operator>=(nullopt_t, const optional<T> &v) noexcept
+{
+    return !v.has_value();
+}
+
+template <typename T, typename U>
+constexpr bool operator==(const optional<T> &l, const U &r) noexcept(
+    noexcept(static_cast<bool>(std::declval<const T &>() == std::declval<const U &>())))
+{
+    if(l)
+        return *l == r;
+    return false;
+}
+
+template <typename T, typename U>
+constexpr bool operator==(const U &l, const optional<T> &r) noexcept(
+    noexcept(static_cast<bool>(std::declval<const U &>() == std::declval<const T &>())))
+{
+    if(r)
+        return l == *r;
+    return false;
+}
+
+template <typename T, typename U>
+constexpr bool operator!=(const optional<T> &l, const U &r) noexcept(
+    noexcept(static_cast<bool>(std::declval<const T &>() != std::declval<const U &>())))
+{
+    if(l)
+        return *l != r;
+    return true;
+}
+
+template <typename T, typename U>
+constexpr bool operator!=(const U &l, const optional<T> &r) noexcept(
+    noexcept(static_cast<bool>(std::declval<const U &>() != std::declval<const T &>())))
+{
+    if(r)
+        return l != *r;
+    return true;
+}
+
+template <typename T, typename U>
+constexpr bool operator<(const optional<T> &l, const U &r) noexcept(
+    noexcept(static_cast<bool>(std::declval<const T &>() < std::declval<const U &>())))
+{
+    if(l)
+        return *l < r;
+    return true;
+}
+
+template <typename T, typename U>
+constexpr bool operator<(const U &l, const optional<T> &r) noexcept(
+    noexcept(static_cast<bool>(std::declval<const U &>() < std::declval<const T &>())))
+{
+    if(r)
+        return l < *r;
+    return false;
+}
+
+template <typename T, typename U>
+constexpr bool operator>(const optional<T> &l, const U &r) noexcept(
+    noexcept(static_cast<bool>(std::declval<const T &>() > std::declval<const U &>())))
+{
+    if(l)
+        return *l > r;
+    return false;
+}
+
+template <typename T, typename U>
+constexpr bool operator>(const U &l, const optional<T> &r) noexcept(
+    noexcept(static_cast<bool>(std::declval<const U &>() > std::declval<const T &>())))
+{
+    if(r)
+        return l > *r;
+    return true;
+}
+
+template <typename T, typename U>
+constexpr bool operator<=(const optional<T> &l, const U &r) noexcept(
+    noexcept(static_cast<bool>(std::declval<const T &>() <= std::declval<const U &>())))
+{
+    if(l)
+        return *l <= r;
+    return true;
+}
+
+template <typename T, typename U>
+constexpr bool operator<=(const U &l, const optional<T> &r) noexcept(
+    noexcept(static_cast<bool>(std::declval<const U &>() <= std::declval<const T &>())))
+{
+    if(r)
+        return l <= *r;
+    return false;
+}
+
+template <typename T, typename U>
+constexpr bool operator>=(const optional<T> &l, const U &r) noexcept(
+    noexcept(static_cast<bool>(std::declval<const T &>() >= std::declval<const U &>())))
+{
+    if(l)
+        return *l >= r;
+    return false;
+}
+
+template <typename T, typename U>
+constexpr bool operator>=(const U &l, const optional<T> &r) noexcept(
+    noexcept(static_cast<bool>(std::declval<const U &>() >= std::declval<const T &>())))
+{
+    if(r)
+        return l >= *r;
+    return true;
+}
+
+template <typename T>
+constexpr optional<typename std::decay<T>::type> make_optional(T &&value)
+{
+    return optional<typename std::decay<T>::type>(in_place, std::forward<T>(value));
+}
+
+template <typename T, typename... Args>
+constexpr optional<T> make_optional(Args &&... args)
+{
+    return optional<T>(in_place, std::forward<T>(args)...);
+}
+
+template <typename T, typename U, typename... Args>
+constexpr optional<T> make_optional(std::initializer_list<U> init_list, Args &&... args)
+{
+    return optional<T>(in_place, init_list, std::forward<T>(args)...);
+}
+
+template <typename T,
+          typename = typename std::enable_if<std::is_move_constructible<T>::value
+                                             && is_swappable<T>::value>::type>
+void swap(optional<T> &l, optional<T> &r) noexcept(noexcept(l.swap(r)))
+{
+    l.swap(r);
+}
+
+namespace detail
+{
+template <typename T, bool Is_Enabled = std::is_default_constructible<std::hash<T>>::value>
+struct optional_hash
+{
+    constexpr std::size_t operator()(const optional<T> &value) const
+        noexcept(noexcept(static_cast<std::size_t>(std::hash<T>()(std::declval<const T &>()))))
+    {
+        if(value)
+            return std::hash<T>()(*value);
+        return 0;
+    }
+};
+
+template <typename T>
+struct optional_hash<T, false>
+{
+    optional_hash() noexcept = delete;
+    ~optional_hash() = delete;
+    optional_hash(const optional_hash &) noexcept = delete;
+    optional_hash &operator=(const optional_hash &) noexcept = delete;
+    std::size_t operator()(const optional<T> &value) const noexcept = delete;
+};
+}
+}
+}
+
+namespace std
+{
+template <typename T>
+struct hash<vulkan_cpu::util::optional<T>> : public vulkan_cpu::util::detail::optional_hash<T>
+{
+};
+}
+
+#endif /* UTIL_OPTIONAL_H_ */