From: Jacob Lifshay Date: Fri, 26 May 2017 09:20:58 +0000 (-0700) Subject: initial commit X-Git-Tag: gsoc-2017~123 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=2361d316713b24628fec8abf07746fc9398e25b4;p=kazan.git initial commit --- 2361d316713b24628fec8abf07746fc9398e25b4 diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..c65d7a3 --- /dev/null +++ b/.clang-format @@ -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 index 0000000..d56ce4a --- /dev/null +++ b/.gitignore @@ -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 index 0000000..e9ef5d7 --- /dev/null +++ b/CMakeLists.txt @@ -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 index 0000000..a89bc8a --- /dev/null +++ b/build/.cproject @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/.project b/build/.project new file mode 100644 index 0000000..d44d09a --- /dev/null +++ b/build/.project @@ -0,0 +1,54 @@ + + + build + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + .clang-format + 1 + WORKSPACE_LOC/.clang-format + + + .gitignore + 1 + WORKSPACE_LOC/.gitignore + + + CMakeLists.txt + 1 + WORKSPACE_LOC/CMakeLists.txt + + + source + 2 + WORKSPACE_LOC/src + + + test-files + 2 + WORKSPACE_LOC/test-files + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..23627cc --- /dev/null +++ b/src/CMakeLists.txt @@ -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 index 0000000..f13abf1 --- /dev/null +++ b/src/demo/CMakeLists.txt @@ -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 index 0000000..65ebb11 --- /dev/null +++ b/src/demo/demo.cpp @@ -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 +#include +#include +#include +#include +#include +#include "../spirv/spirv.h" +#include "../util/optional.h" + +namespace vulkan_cpu +{ +namespace test +{ +util::optional> load_file(const char *fileName) +{ + using spirv::word; + constexpr int eof = std::char_traits::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> blocks; + std::array word_bytes{}; + static_assert(sizeof(word) == 4, ""); + static_assert(std::is_same::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 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(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 &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 index 0000000..c470ba2 --- /dev/null +++ b/src/spirv/CMakeLists.txt @@ -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 index 0000000..1abdc51 --- /dev/null +++ b/src/spirv/spirv.cpp @@ -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 index 0000000..5e564c2 --- /dev/null +++ b/src/spirv/spirv.h @@ -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 + +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 index 0000000..854e345 --- /dev/null +++ b/src/util/CMakeLists.txt @@ -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 index 0000000..76092e1 --- /dev/null +++ b/src/util/in_place.cpp @@ -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 index 0000000..d95ca1b --- /dev/null +++ b/src/util/in_place.h @@ -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 + +namespace vulkan_cpu +{ +namespace util +{ +struct in_place_t +{ + explicit in_place_t() = default; +}; + +constexpr in_place_t in_place{}; + +template +struct in_place_type_t +{ + explicit in_place_type_t() = default; +}; + +template +constexpr in_place_type_t in_place_type{}; + +template +struct in_place_index_t +{ + explicit in_place_index_t() = default; +}; + +template +constexpr in_place_index_t 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 index 0000000..bff1e22 --- /dev/null +++ b/src/util/is_referenceable.cpp @@ -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 index 0000000..9b0c0ea --- /dev/null +++ b/src/util/is_referenceable.h @@ -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 + +namespace vulkan_cpu +{ +namespace util +{ +template +struct is_referenceable + : public std::integral_constant::value || std::is_reference::value> +{ +}; + +template +struct is_referenceable : public std::true_type +{ +}; + +template +struct is_referenceable : 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 index 0000000..51ca86c --- /dev/null +++ b/src/util/is_swappable.cpp @@ -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 index 0000000..b744200 --- /dev/null +++ b/src/util/is_swappable.h @@ -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 +#include +#include "is_referenceable.h" + +namespace vulkan_cpu_util_is_swappable_unrelated_namespace +{ +using std::swap; +template ::value || std::is_void::value> +class is_swappable_with +{ +private: + template (), std::declval()))> + static void fn(int); + template + static char fn(...); + +public: + static constexpr bool value = + std::is_void(0))>::value && std::is_void(0))>::value; +}; + +template +class is_swappable_with +{ +public: + static constexpr bool value = false; +}; + +template ::value> +struct is_nothrow_swappable_with +{ + static constexpr bool value = noexcept(swap(std::declval(), std::declval())) + && noexcept(swap(std::declval(), std::declval())); +}; + +template +struct is_nothrow_swappable_with +{ + static constexpr bool value = false; +}; +} + +namespace vulkan_cpu +{ +namespace util +{ +template +struct is_swappable_with + : public std::integral_constant::value> +{ +}; + +template +struct is_nothrow_swappable_with + : public std::integral_constant::value> +{ +}; + +namespace detail +{ +template ::value> +struct is_swappable_helper +{ + static constexpr bool value = is_swappable_with::value; +}; + +template +struct is_swappable_helper +{ + static constexpr bool value = false; +}; + +template ::value> +struct is_nothrow_swappable_helper +{ + static constexpr bool value = is_nothrow_swappable_with::value; +}; + +template +struct is_nothrow_swappable_helper +{ + static constexpr bool value = false; +}; +} + +template +struct is_swappable : public std::integral_constant::value> +{ +}; + +template +struct is_nothrow_swappable + : public std::integral_constant::value> +{ +}; +} +} + +#endif /* UTIL_IS_SWAPPABLE_H_ */ diff --git a/src/util/optional.cpp b/src/util/optional.cpp new file mode 100644 index 0000000..bfccd96 --- /dev/null +++ b/src/util/optional.cpp @@ -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 index 0000000..699d700 --- /dev/null +++ b/src/util/optional.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#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 ::value, + bool Is_Trivially_Copyable = std::is_trivially_copyable::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 + T &emplace(Types &&... args) noexcept(std::is_nothrow_constructible::value) + { + reset(); + ::new(static_cast(std::addressof(full_value))) T(std::forward(args)...); + is_full = true; + return full_value; + } + template < + typename U, + typename... Types, + typename = typename std:: + enable_if, Types...>::value>::type> + T &emplace(std::initializer_list init_list, Types &&... args) noexcept( + std::is_nothrow_constructible, Types...>::value) + { + reset(); + ::new(static_cast(std::addressof(full_value))) + T(init_list, std::forward(args)...); + is_full = true; + return full_value; + } + optional_base(const optional_base &rt) noexcept(std::is_nothrow_copy_constructible::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::value) + : empty_value{}, is_full(false) + { + if(rt.is_full) + emplace(std::move(rt.full_value)); + } + template ::value>::type> + constexpr explicit optional_base(in_place_t, Types &&... args) noexcept( + std::is_nothrow_constructible::value) + : full_value(std::forward(args)...), is_full(true) + { + } + template < + typename U, + typename... Types, + typename = typename std:: + enable_if, Types...>::value>::type> + constexpr explicit optional_base( + in_place_t, + std::initializer_list init_list, + Types &&... args) noexcept(std::is_nothrow_constructible::value) + : full_value(init_list, std::forward(args)...), is_full(true) + { + } + ~optional_base() + { + reset(); + } + optional_base &operator=(const optional_base &rt) noexcept( + std::is_nothrow_copy_assignable::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::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 +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 + { + // full_value.~T() not needed + } + template + T &emplace(Types &&... args) noexcept(std::is_nothrow_constructible::value) + { + reset(); + ::new(static_cast(std::addressof(full_value))) T(std::forward(args)...); + is_full = true; + return full_value; + } + template < + typename U, + typename... Types, + typename = typename std:: + enable_if, Types...>::value>::type> + T &emplace(std::initializer_list init_list, Types &&... args) noexcept( + std::is_nothrow_constructible, Types...>::value) + { + reset(); + ::new(static_cast(std::addressof(full_value))) + T(init_list, std::forward(args)...); + is_full = true; + return full_value; + } + optional_base(const optional_base &rt) noexcept(std::is_nothrow_copy_constructible::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::value) + : empty_value{}, is_full(false) + { + if(rt.is_full) + emplace(std::move(rt.full_value)); + } + template ::value>::type> + constexpr explicit optional_base(in_place_t, Types &&... args) noexcept( + std::is_nothrow_constructible::value) + : full_value(std::forward(args)...), is_full(true) + { + } + template < + typename U, + typename... Types, + typename = typename std:: + enable_if, Types...>::value>::type> + constexpr explicit optional_base( + in_place_t, + std::initializer_list init_list, + Types &&... args) noexcept(std::is_nothrow_constructible::value) + : full_value(init_list, std::forward(args)...), is_full(true) + { + } + ~optional_base() = default; + optional_base &operator=(const optional_base &rt) noexcept( + std::is_nothrow_copy_assignable::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::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 +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 + { + // full_value.~T() not needed + } + template + T &emplace(Types &&... args) noexcept(std::is_nothrow_constructible::value) + { + reset(); + ::new(static_cast(std::addressof(full_value))) T(std::forward(args)...); + is_full = true; + return full_value; + } + template < + typename U, + typename... Types, + typename = typename std:: + enable_if, Types...>::value>::type> + T &emplace(std::initializer_list init_list, Types &&... args) noexcept( + std::is_nothrow_constructible, Types...>::value) + { + reset(); + ::new(static_cast(std::addressof(full_value))) + T(init_list, std::forward(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 ::value>::type> + constexpr explicit optional_base(in_place_t, Types &&... args) noexcept( + std::is_nothrow_constructible::value) + : full_value(std::forward(args)...), is_full(true) + { + } + template < + typename U, + typename... Types, + typename = typename std:: + enable_if, Types...>::value>::type> + constexpr explicit optional_base( + in_place_t, + std::initializer_list init_list, + Types &&... args) noexcept(std::is_nothrow_constructible::value) + : full_value(init_list, std::forward(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 +class optional; + +namespace detail +{ +template +constexpr bool optional_needs_conversion_constructors() noexcept +{ + if(!std::is_constructible::value) + return false; + if(std::is_constructible &>::value) + return false; + if(std::is_constructible &>::value) + return false; + if(std::is_constructible &&>::value) + return false; + if(std::is_constructible &&>::value) + return false; + if(std::is_convertible &, T>::value) + return false; + if(std::is_convertible &, T>::value) + return false; + if(std::is_convertible &&, T>::value) + return false; + if(std::is_convertible &&, T>::value) + return false; + return true; +} + +template +constexpr bool optional_needs_conversion_from_optional_assign_operators() noexcept +{ + if(!std::is_constructible::value) + return false; + if(!std::is_assignable::value) + return false; + if(std::is_constructible &>::value) + return false; + if(std::is_constructible &>::value) + return false; + if(std::is_constructible &&>::value) + return false; + if(std::is_constructible &&>::value) + return false; + if(std::is_convertible &, T>::value) + return false; + if(std::is_convertible &, T>::value) + return false; + if(std::is_convertible &&, T>::value) + return false; + if(std::is_convertible &&, T>::value) + return false; + if(std::is_assignable &>::value) + return false; + if(std::is_assignable &>::value) + return false; + if(std::is_assignable &&>::value) + return false; + if(std::is_assignable &&>::value) + return false; + return true; +} +} + +template +class optional : private detail::optional_base +{ +private: + typedef detail::optional_base base; + using base::is_full; + using base::full_value; + +public: + using base::base; + using base::operator=; + using base::reset; + constexpr optional() noexcept = default; + template () + && std::is_convertible::value>::type> + optional(const optional &rt) noexcept(std::is_nothrow_constructible::value) + : base() + { + if(rt) + emplace(*rt); + } + template () + && !std::is_convertible::value>::type, + typename = void> + explicit optional(const optional &rt) noexcept( + std::is_nothrow_constructible::value) + : base() + { + if(rt) + emplace(*rt); + } + template < + typename U, + typename = + typename std::enable_if() + && std::is_convertible::value>::type> + optional(optional &&rt) noexcept(std::is_nothrow_constructible::value) + : base() + { + if(rt) + emplace(std::move(*rt)); + } + template < + typename U, + typename = + typename std::enable_if() + && !std::is_convertible::value>::type, + typename = void> + explicit optional(optional &&rt) noexcept(std::is_nothrow_constructible::value) + : base() + { + if(rt) + emplace(std::move(*rt)); + } + template ::value + && !std::is_same::type, in_place_t>::value + && !std::is_same::type, optional>::value + && std::is_convertible::value>::type, + typename = void> + constexpr optional(U &&value) noexcept(std::is_nothrow_constructible::value) + : base(in_place, std::forward(value)) + { + } + template ::value + && !std::is_same::type, in_place_t>::value + && !std::is_same::type, optional>::value + && !std::is_convertible::value>::type> + explicit constexpr optional(U &&value) noexcept(std::is_nothrow_constructible::value) + : base(in_place, std::forward(value)) + { + } + template ::type, optional>::value + && std::is_constructible::value + && std::is_assignable::value + && (!std::is_scalar::value + || !std::is_same::type, T>::value)>::type> + optional &operator=(U &&value) noexcept(std::is_nothrow_constructible::value + &&std::is_nothrow_assignable::value) + { + if(is_full) + full_value = std::forward(value); + else + emplace(std::forward(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()>:: + type> + optional &operator=(const optional &rt) noexcept( + std::is_nothrow_constructible::value + &&std::is_nothrow_assignable::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()>::type> + optional &operator=(optional &&rt) noexcept(std::is_nothrow_constructible::value && + std::is_nothrow_assignable::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 + constexpr T value_or(U &&default_value) const &noexcept( + std::is_nothrow_copy_constructible::value // + &&noexcept(static_cast(std::declval()))) + { + return is_full ? full_value : static_cast(std::forward(default_value)); + } + template + constexpr T value_or(U &&default_value) + && noexcept(std::is_nothrow_copy_constructible::value // + &&noexcept(static_cast(std::declval()))) + { + return is_full ? std::move(full_value) : static_cast(std::forward(default_value)); + } + void swap(optional &other) noexcept( + std::is_nothrow_move_constructible::value &&util::is_nothrow_swappable::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 +constexpr bool operator==(const optional &l, const optional &r) noexcept(noexcept(*l == *r)) +{ + if(!l.has_value() || !r.has_value()) + return !r.has_value(); + return *l == *r; +} + +template +constexpr bool operator!=(const optional &l, const optional &r) noexcept(noexcept(*l == *r)) +{ + if(!l.has_value() || !r.has_value()) + return r.has_value(); + return *l != *r; +} + +template +constexpr bool operator<(const optional &l, const optional &r) noexcept(noexcept(*l == *r)) +{ + if(!l.has_value() || !r.has_value()) + return r.has_value(); + return *l < *r; +} + +template +constexpr bool operator>(const optional &l, const optional &r) noexcept(noexcept(*l == *r)) +{ + if(!l.has_value() || !r.has_value()) + return l.has_value(); + return *l > *r; +} + +template +constexpr bool operator<=(const optional &l, const optional &r) noexcept(noexcept(*l == *r)) +{ + if(!l.has_value() || !r.has_value()) + return !l.has_value(); + return *l <= *r; +} + +template +constexpr bool operator>=(const optional &l, const optional &r) noexcept(noexcept(*l == *r)) +{ + if(!l.has_value() || !r.has_value()) + return !r.has_value(); + return *l >= *r; +} + +template +constexpr bool operator==(const optional &v, nullopt_t) noexcept +{ + return !v.has_value(); +} + +template +constexpr bool operator!=(const optional &v, nullopt_t) noexcept +{ + return v.has_value(); +} + +template +constexpr bool operator<(const optional &v, nullopt_t) noexcept +{ + return false; +} + +template +constexpr bool operator>(const optional &v, nullopt_t) noexcept +{ + return v.has_value(); +} + +template +constexpr bool operator<=(const optional &v, nullopt_t) noexcept +{ + return !v.has_value(); +} + +template +constexpr bool operator>=(const optional &v, nullopt_t) noexcept +{ + return true; +} + +template +constexpr bool operator==(nullopt_t, const optional &v) noexcept +{ + return !v.has_value(); +} + +template +constexpr bool operator!=(nullopt_t, const optional &v) noexcept +{ + return v.has_value(); +} + +template +constexpr bool operator<(nullopt_t, const optional &v) noexcept +{ + return v.has_value(); +} + +template +constexpr bool operator>(nullopt_t, const optional &v) noexcept +{ + return false; +} + +template +constexpr bool operator<=(nullopt_t, const optional &v) noexcept +{ + return true; +} + +template +constexpr bool operator>=(nullopt_t, const optional &v) noexcept +{ + return !v.has_value(); +} + +template +constexpr bool operator==(const optional &l, const U &r) noexcept( + noexcept(static_cast(std::declval() == std::declval()))) +{ + if(l) + return *l == r; + return false; +} + +template +constexpr bool operator==(const U &l, const optional &r) noexcept( + noexcept(static_cast(std::declval() == std::declval()))) +{ + if(r) + return l == *r; + return false; +} + +template +constexpr bool operator!=(const optional &l, const U &r) noexcept( + noexcept(static_cast(std::declval() != std::declval()))) +{ + if(l) + return *l != r; + return true; +} + +template +constexpr bool operator!=(const U &l, const optional &r) noexcept( + noexcept(static_cast(std::declval() != std::declval()))) +{ + if(r) + return l != *r; + return true; +} + +template +constexpr bool operator<(const optional &l, const U &r) noexcept( + noexcept(static_cast(std::declval() < std::declval()))) +{ + if(l) + return *l < r; + return true; +} + +template +constexpr bool operator<(const U &l, const optional &r) noexcept( + noexcept(static_cast(std::declval() < std::declval()))) +{ + if(r) + return l < *r; + return false; +} + +template +constexpr bool operator>(const optional &l, const U &r) noexcept( + noexcept(static_cast(std::declval() > std::declval()))) +{ + if(l) + return *l > r; + return false; +} + +template +constexpr bool operator>(const U &l, const optional &r) noexcept( + noexcept(static_cast(std::declval() > std::declval()))) +{ + if(r) + return l > *r; + return true; +} + +template +constexpr bool operator<=(const optional &l, const U &r) noexcept( + noexcept(static_cast(std::declval() <= std::declval()))) +{ + if(l) + return *l <= r; + return true; +} + +template +constexpr bool operator<=(const U &l, const optional &r) noexcept( + noexcept(static_cast(std::declval() <= std::declval()))) +{ + if(r) + return l <= *r; + return false; +} + +template +constexpr bool operator>=(const optional &l, const U &r) noexcept( + noexcept(static_cast(std::declval() >= std::declval()))) +{ + if(l) + return *l >= r; + return false; +} + +template +constexpr bool operator>=(const U &l, const optional &r) noexcept( + noexcept(static_cast(std::declval() >= std::declval()))) +{ + if(r) + return l >= *r; + return true; +} + +template +constexpr optional::type> make_optional(T &&value) +{ + return optional::type>(in_place, std::forward(value)); +} + +template +constexpr optional make_optional(Args &&... args) +{ + return optional(in_place, std::forward(args)...); +} + +template +constexpr optional make_optional(std::initializer_list init_list, Args &&... args) +{ + return optional(in_place, init_list, std::forward(args)...); +} + +template ::value + && is_swappable::value>::type> +void swap(optional &l, optional &r) noexcept(noexcept(l.swap(r))) +{ + l.swap(r); +} + +namespace detail +{ +template >::value> +struct optional_hash +{ + constexpr std::size_t operator()(const optional &value) const + noexcept(noexcept(static_cast(std::hash()(std::declval())))) + { + if(value) + return std::hash()(*value); + return 0; + } +}; + +template +struct optional_hash +{ + 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 &value) const noexcept = delete; +}; +} +} +} + +namespace std +{ +template +struct hash> : public vulkan_cpu::util::detail::optional_hash +{ +}; +} + +#endif /* UTIL_OPTIONAL_H_ */