From 7eb1d05f63c7ba8df6a203138932ea428ab4aa49 Mon Sep 17 00:00:00 2001 From: Merry Date: Tue, 19 Apr 2022 16:27:52 +0100 Subject: [PATCH] Squashed 'externals/mcl/' content from commit a86a53843 git-subtree-dir: externals/mcl git-subtree-split: a86a53843f82e4d6ca2f2e1437824495acad2712 --- .clang-format | 218 ++++++++++ .gitignore | 2 + CMakeLists.txt | 126 ++++++ .../CreateTargetDirectoryGroups.cmake | 17 + CMakeModules/DetectArchitecture.cmake | 56 +++ CMakeModules/mclConfig.cmake.in | 5 + LICENSE | 21 + README | 17 + include/mcl/assert.hpp | 61 +++ include/mcl/bit/bit_count.hpp | 54 +++ include/mcl/bit/bit_field.hpp | 203 ++++++++++ include/mcl/bit/rotate.hpp | 31 ++ include/mcl/bit/swap.hpp | 50 +++ include/mcl/bit_cast.hpp | 36 ++ include/mcl/bitsizeof.hpp | 15 + include/mcl/concepts/bit_integral.hpp | 16 + include/mcl/concepts/is_any_of.hpp | 14 + include/mcl/concepts/same_as.hpp | 19 + include/mcl/container/intrusive_list.hpp | 378 ++++++++++++++++++ include/mcl/hint/assume.hpp | 13 + include/mcl/iterator/reverse.hpp | 34 ++ include/mcl/macro/anonymous_variable.hpp | 13 + include/mcl/macro/architecture.hpp | 40 ++ include/mcl/macro/concatenate_tokens.hpp | 8 + include/mcl/mp/metafunction/apply.hpp | 25 ++ include/mcl/mp/metafunction/bind.hpp | 18 + include/mcl/mp/metafunction/identity.hpp | 22 + include/mcl/mp/metafunction/map.hpp | 25 ++ include/mcl/mp/metavalue/bit_and.hpp | 19 + include/mcl/mp/metavalue/bit_not.hpp | 19 + include/mcl/mp/metavalue/bit_or.hpp | 19 + include/mcl/mp/metavalue/bit_xor.hpp | 19 + include/mcl/mp/metavalue/conjunction.hpp | 42 ++ include/mcl/mp/metavalue/disjunction.hpp | 42 ++ include/mcl/mp/metavalue/lift_value.hpp | 15 + include/mcl/mp/metavalue/logic_and.hpp | 19 + include/mcl/mp/metavalue/logic_if.hpp | 21 + include/mcl/mp/metavalue/logic_not.hpp | 19 + include/mcl/mp/metavalue/logic_or.hpp | 19 + include/mcl/mp/metavalue/product.hpp | 19 + include/mcl/mp/metavalue/sum.hpp | 19 + include/mcl/mp/metavalue/value.hpp | 30 ++ include/mcl/mp/metavalue/value_cast.hpp | 15 + include/mcl/mp/metavalue/value_equal.hpp | 15 + include/mcl/mp/misc/argument_count.hpp | 19 + include/mcl/mp/typelist/append.hpp | 25 ++ include/mcl/mp/typelist/cartesian_product.hpp | 47 +++ include/mcl/mp/typelist/concat.hpp | 94 +++++ include/mcl/mp/typelist/contains.hpp | 23 ++ include/mcl/mp/typelist/drop.hpp | 33 ++ include/mcl/mp/typelist/get.hpp | 18 + include/mcl/mp/typelist/head.hpp | 25 ++ include/mcl/mp/typelist/length.hpp | 20 + include/mcl/mp/typelist/lift_sequence.hpp | 29 ++ include/mcl/mp/typelist/list.hpp | 13 + include/mcl/mp/typelist/lower_to_tuple.hpp | 24 ++ include/mcl/mp/typelist/prepend.hpp | 25 ++ include/mcl/mp/typelist/tail.hpp | 25 ++ include/mcl/scope_exit.hpp | 85 ++++ include/mcl/stdint.hpp | 27 ++ include/mcl/type_traits/function_info.hpp | 70 ++++ include/mcl/type_traits/integer_of_size.hpp | 48 +++ .../type_traits/is_instance_of_template.hpp | 22 + src/CMakeLists.txt | 69 ++++ src/assert.cpp | 20 + tests/CMakeLists.txt | 14 + tests/main.cpp | 6 + tests/mp/metavalue_tests.cpp | 90 +++++ tests/mp/typelist_tests.cpp | 104 +++++ tests/type_traits/type_traits_tests.cpp | 39 ++ 70 files changed, 2902 insertions(+) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 CMakeModules/CreateTargetDirectoryGroups.cmake create mode 100644 CMakeModules/DetectArchitecture.cmake create mode 100644 CMakeModules/mclConfig.cmake.in create mode 100644 LICENSE create mode 100644 README create mode 100644 include/mcl/assert.hpp create mode 100644 include/mcl/bit/bit_count.hpp create mode 100644 include/mcl/bit/bit_field.hpp create mode 100644 include/mcl/bit/rotate.hpp create mode 100644 include/mcl/bit/swap.hpp create mode 100644 include/mcl/bit_cast.hpp create mode 100644 include/mcl/bitsizeof.hpp create mode 100644 include/mcl/concepts/bit_integral.hpp create mode 100644 include/mcl/concepts/is_any_of.hpp create mode 100644 include/mcl/concepts/same_as.hpp create mode 100644 include/mcl/container/intrusive_list.hpp create mode 100644 include/mcl/hint/assume.hpp create mode 100644 include/mcl/iterator/reverse.hpp create mode 100644 include/mcl/macro/anonymous_variable.hpp create mode 100644 include/mcl/macro/architecture.hpp create mode 100644 include/mcl/macro/concatenate_tokens.hpp create mode 100644 include/mcl/mp/metafunction/apply.hpp create mode 100644 include/mcl/mp/metafunction/bind.hpp create mode 100644 include/mcl/mp/metafunction/identity.hpp create mode 100644 include/mcl/mp/metafunction/map.hpp create mode 100644 include/mcl/mp/metavalue/bit_and.hpp create mode 100644 include/mcl/mp/metavalue/bit_not.hpp create mode 100644 include/mcl/mp/metavalue/bit_or.hpp create mode 100644 include/mcl/mp/metavalue/bit_xor.hpp create mode 100644 include/mcl/mp/metavalue/conjunction.hpp create mode 100644 include/mcl/mp/metavalue/disjunction.hpp create mode 100644 include/mcl/mp/metavalue/lift_value.hpp create mode 100644 include/mcl/mp/metavalue/logic_and.hpp create mode 100644 include/mcl/mp/metavalue/logic_if.hpp create mode 100644 include/mcl/mp/metavalue/logic_not.hpp create mode 100644 include/mcl/mp/metavalue/logic_or.hpp create mode 100644 include/mcl/mp/metavalue/product.hpp create mode 100644 include/mcl/mp/metavalue/sum.hpp create mode 100644 include/mcl/mp/metavalue/value.hpp create mode 100644 include/mcl/mp/metavalue/value_cast.hpp create mode 100644 include/mcl/mp/metavalue/value_equal.hpp create mode 100644 include/mcl/mp/misc/argument_count.hpp create mode 100644 include/mcl/mp/typelist/append.hpp create mode 100644 include/mcl/mp/typelist/cartesian_product.hpp create mode 100644 include/mcl/mp/typelist/concat.hpp create mode 100644 include/mcl/mp/typelist/contains.hpp create mode 100644 include/mcl/mp/typelist/drop.hpp create mode 100644 include/mcl/mp/typelist/get.hpp create mode 100644 include/mcl/mp/typelist/head.hpp create mode 100644 include/mcl/mp/typelist/length.hpp create mode 100644 include/mcl/mp/typelist/lift_sequence.hpp create mode 100644 include/mcl/mp/typelist/list.hpp create mode 100644 include/mcl/mp/typelist/lower_to_tuple.hpp create mode 100644 include/mcl/mp/typelist/prepend.hpp create mode 100644 include/mcl/mp/typelist/tail.hpp create mode 100644 include/mcl/scope_exit.hpp create mode 100644 include/mcl/stdint.hpp create mode 100644 include/mcl/type_traits/function_info.hpp create mode 100644 include/mcl/type_traits/integer_of_size.hpp create mode 100644 include/mcl/type_traits/is_instance_of_template.hpp create mode 100644 src/CMakeLists.txt create mode 100644 src/assert.cpp create mode 100644 tests/CMakeLists.txt create mode 100644 tests/main.cpp create mode 100644 tests/mp/metavalue_tests.cpp create mode 100644 tests/mp/typelist_tests.cpp create mode 100644 tests/type_traits/type_traits_tests.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..5c5555ea --- /dev/null +++ b/.clang-format @@ -0,0 +1,218 @@ +--- +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignConsecutiveMacros: None +AlignEscapedNewlines: Right +AlignOperands: AlignAfterOperator +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: false +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: All +BreakBeforeBraces: Custom +BreakBeforeConceptDeclarations: true +BreakBeforeTernaryOperators: true +BreakBeforeInheritanceComma: false +BreakConstructorInitializersBeforeComma: true +BreakConstructorInitializers: BeforeComma +BreakInheritanceList: BeforeComma +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 0 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +# EmptyLineAfterAccessModifier: Leave +EmptyLineBeforeAccessModifier: Always +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: '(^)|(^)|(^)' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<([^\.])*>$' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*\.' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 4 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '([-_](test|unittest))?$' +IncludeIsMainSourceRegex: '' +# IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: NoIndent +IndentGotoLabels: false +IndentPPDirectives: AfterHash +IndentRequires: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +# InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +NamespaceMacros: +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Left +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + CanonicalDelimiter: '' + BasedOnStyle: google +ReflowComments: true +# ShortNamespaceLines: 5 +SortIncludes: true +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false +# SpacesInLineCommentPrefix: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +TypenameMacros: +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME + - FCODE + - ICODE +... + diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..547b4ec7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*build*/ +.DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..c1c28f61 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,126 @@ +cmake_minimum_required(VERSION 3.12 FATAL_ERROR) +include(GNUInstallDirs) + +project(mcl LANGUAGES CXX VERSION 0.1.3) + +# Project options +option(MCL_WARNINGS_AS_ERRORS "Warnings as errors" ON) + +# Default to a Release build +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) + message(STATUS "Defaulting to a Release build") +endif() + +# Set hard requirements for C++ +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +# Warn on CMake API deprecations +set(CMAKE_WARN_DEPRECATED ON) + +# Disable in-source builds +set(CMAKE_DISABLE_SOURCE_CHANGES ON) +set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) +if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") + message(SEND_ERROR "In-source builds are not allowed.") +endif() + +# Add the module directory to the list of paths +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") + +# Compiler flags +if (MSVC) + set(MCL_CXX_FLAGS + /std:c++latest + /experimental:external + /external:W0 + /external:anglebrackets + /W4 + /w44263 # Non-virtual member function hides base class virtual function + /w44265 # Class has virtual functions, but destructor is not virtual + /w44456 # Declaration of 'var' hides previous local declaration + /w44457 # Declaration of 'var' hides function parameter + /w44458 # Declaration of 'var' hides class member + /w44459 # Declaration of 'var' hides global definition + /w44946 # Reinterpret-cast between related types + /wd4592 # Symbol will be dynamically initialized (implementation limitation) + /permissive- # Stricter C++ standards conformance + /MP + /Zi + /Zo + /EHsc + /Zc:externConstexpr # Allows external linkage for variables declared "extern constexpr", as the standard permits. + /Zc:inline # Omits inline functions from object-file output. + /Zc:throwingNew # Assumes new (without std::nothrow) never returns null. + /volatile:iso # Use strict standard-abiding volatile semantics + /bigobj # Increase number of sections in .obj files + /DNOMINMAX) + + if (MCL_WARNINGS_AS_ERRORS) + list(APPEND MCL_CXX_FLAGS /WX) + endif() + + if (CMAKE_VS_PLATFORM_TOOLSET MATCHES "LLVM-vs[0-9]+") + list(APPEND MCL_CXX_FLAGS + -Qunused-arguments + -Wno-missing-braces) + endif() +else() + set(MCL_CXX_FLAGS + -Wall + -Wextra + -Wcast-qual + -pedantic + -pedantic-errors + -Wfatal-errors + -Wno-missing-braces) + + if (MCL_WARNINGS_AS_ERRORS) + list(APPEND MCL_CXX_FLAGS -Werror) + endif() +endif() + +# Dependencies + +if (NOT TARGET Catch2::Catch2) + find_package(Catch2 QUIET) +endif() + +if (NOT TARGET fmt::fmt) + find_package(fmt REQUIRED) +endif() + +# Project files + +add_subdirectory(src) +if (TARGET Catch2::Catch2) + add_subdirectory(tests) +endif() + +# Install instructions + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +install(TARGETS mcl EXPORT mclTargets) +install(EXPORT mclTargets + NAMESPACE merry:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/mcl" +) + +configure_package_config_file(CMakeModules/mclConfig.cmake.in + mclConfig.cmake + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/mcl" +) +write_basic_package_version_file(mclConfigVersion.cmake + COMPATIBILITY SameMajorVersion +) +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/mclConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/mclConfigVersion.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/mcl" +) + +install(DIRECTORY include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp") diff --git a/CMakeModules/CreateTargetDirectoryGroups.cmake b/CMakeModules/CreateTargetDirectoryGroups.cmake new file mode 100644 index 00000000..175899e7 --- /dev/null +++ b/CMakeModules/CreateTargetDirectoryGroups.cmake @@ -0,0 +1,17 @@ +# This function should be passed a name of an existing target. It will automatically generate +# file groups following the directory hierarchy, so that the layout of the files in IDEs matches the +# one in the filesystem. +function(create_target_directory_groups target_name) + # Place any files that aren't in the source list in a separate group so that they don't get in + # the way. + source_group("Other Files" REGULAR_EXPRESSION ".") + + get_target_property(target_sources "${target_name}" SOURCES) + + foreach(file_name IN LISTS target_sources) + get_filename_component(dir_name "${file_name}" PATH) + # Group names use '\' as a separator even though the entire rest of CMake uses '/'... + string(REPLACE "/" "\\" group_name "${dir_name}") + source_group("${group_name}" FILES "${file_name}") + endforeach() +endfunction() diff --git a/CMakeModules/DetectArchitecture.cmake b/CMakeModules/DetectArchitecture.cmake new file mode 100644 index 00000000..1fbd5e9d --- /dev/null +++ b/CMakeModules/DetectArchitecture.cmake @@ -0,0 +1,56 @@ +include(CheckSymbolExists) + +function(detect_architecture symbol arch) + if (NOT DEFINED ARCHITECTURE) + set(CMAKE_REQUIRED_QUIET YES) + check_symbol_exists("${symbol}" "" DETECT_ARCHITECTURE_${arch}) + unset(CMAKE_REQUIRED_QUIET) + + if (DETECT_ARCHITECTURE_${arch}) + set(ARCHITECTURE "${arch}" PARENT_SCOPE) + endif() + + unset(DETECT_ARCHITECTURE_${arch} CACHE) + endif() +endfunction() + +detect_architecture("__ARM64__" arm64) +detect_architecture("__aarch64__" arm64) +detect_architecture("_M_ARM64" arm64) + +detect_architecture("__arm__" arm32) +detect_architecture("__TARGET_ARCH_ARM" arm32) +detect_architecture("_M_ARM" arm32) + +detect_architecture("__x86_64" x86_64) +detect_architecture("__x86_64__" x86_64) +detect_architecture("__amd64" x86_64) +detect_architecture("_M_X64" x86_64) + +detect_architecture("__i386" x86_32) +detect_architecture("__i386__" x86_32) +detect_architecture("_M_IX86" x86_32) + +detect_architecture("__ia64" ia64) +detect_architecture("__ia64__" ia64) +detect_architecture("_M_IA64" ia64) + +detect_architecture("__mips" mips) +detect_architecture("__mips__" mips) +detect_architecture("_M_MRX000" mips) + +detect_architecture("__ppc64__" ppc64) +detect_architecture("__powerpc64__" ppc64) + +detect_architecture("__ppc__" ppc32) +detect_architecture("__ppc" ppc32) +detect_architecture("__powerpc__" ppc32) +detect_architecture("_ARCH_COM" ppc32) +detect_architecture("_ARCH_PWR" ppc32) +detect_architecture("_ARCH_PPC" ppc32) +detect_architecture("_M_MPPC" ppc32) +detect_architecture("_M_PPC" ppc32) + +detect_architecture("__riscv" riscv) + +detect_architecture("__EMSCRIPTEN__" wasm) diff --git a/CMakeModules/mclConfig.cmake.in b/CMakeModules/mclConfig.cmake.in new file mode 100644 index 00000000..8c9ad12a --- /dev/null +++ b/CMakeModules/mclConfig.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") + +check_required_components(@PROJECT_NAME@) diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..614ef755 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 merryhime + +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. diff --git a/README b/README new file mode 100644 index 00000000..55feaceb --- /dev/null +++ b/README @@ -0,0 +1,17 @@ + + oooo + `888 + ooo. .oo. .oo. .ooooo. 888 + `888P"Y88bP"Y88b d88' `"Y8 888 + 888 888 888 888 888 + 888 888 888 888 .o8 888 + o888o o888o o888o `Y8bod8P' o888o + + + .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. + / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ +`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-` + +A collection of C++20 utilities which is common to a number of merry's projects. + +MIT licensed. diff --git a/include/mcl/assert.hpp b/include/mcl/assert.hpp new file mode 100644 index 00000000..3b9377a7 --- /dev/null +++ b/include/mcl/assert.hpp @@ -0,0 +1,61 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include + +#include "mcl/hint/assume.hpp" + +namespace mcl::detail { + +[[noreturn]] void assert_terminate_impl(fmt::string_view msg, fmt::format_args args); + +template +[[noreturn]] void assert_terminate(fmt::string_view msg, Ts... args) { + assert_terminate_impl(msg, fmt::make_format_args(args...)); +} + +} // namespace mcl::detail + +#define UNREACHABLE() ASSERT_FALSE("Unreachable code!") + +#define ASSERT(expr) \ + [&] { \ + if (std::is_constant_evaluated()) { \ + if (!(expr)) { \ + throw std::logic_error{"ASSERT failed at compile time"}; \ + } \ + } else { \ + if (!(expr)) [[unlikely]] { \ + ::mcl::detail::assert_terminate(#expr); \ + } \ + } \ + }() + +#define ASSERT_MSG(expr, ...) \ + [&] { \ + if (std::is_constant_evaluated()) { \ + if (!(expr)) { \ + throw std::logic_error{"ASSERT_MSG failed at compile time"}; \ + } \ + } else { \ + if (!(expr)) [[unlikely]] { \ + ::mcl::detail::assert_terminate(#expr "\nMessage: " __VA_ARGS__); \ + } \ + } \ + }() + +#define ASSERT_FALSE(...) ::mcl::detail::assert_terminate("false\nMessage: " __VA_ARGS__) + +#if defined(NDEBUG) || defined(MCL_IGNORE_ASSERTS) +# define DEBUG_ASSERT(expr) ASSUME(expr) +# define DEBUG_ASSERT_MSG(expr, ...) ASSUME(expr) +#else +# define DEBUG_ASSERT(expr) ASSERT(expr) +# define DEBUG_ASSERT_MSG(expr, ...) ASSERT_MSG(expr, __VA_ARGS__) +#endif diff --git a/include/mcl/bit/bit_count.hpp b/include/mcl/bit/bit_count.hpp new file mode 100644 index 00000000..c08abd00 --- /dev/null +++ b/include/mcl/bit/bit_count.hpp @@ -0,0 +1,54 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "mcl/bitsizeof.hpp" +#include "mcl/concepts/bit_integral.hpp" +#include "mcl/stdint.hpp" + +namespace mcl::bit { + +template +inline size_t count_ones(T x) { + return std::bitset>(x).count(); +} + +template +constexpr size_t count_leading_zeros(T x) { + size_t result = bitsizeof; + while (x != 0) { + x >>= 1; + result--; + } + return result; +} + +template +constexpr int highest_set_bit(T x) { + int result = -1; + while (x != 0) { + x >>= 1; + result++; + } + return result; +} + +template +constexpr size_t lowest_set_bit(T x) { + if (x == 0) { + return bitsizeof; + } + + size_t result = 0; + while ((x & 1) == 0) { + x >>= 1; + result++; + } + return result; +} + +} // namespace mcl::bit diff --git a/include/mcl/bit/bit_field.hpp b/include/mcl/bit/bit_field.hpp new file mode 100644 index 00000000..e4fca8ef --- /dev/null +++ b/include/mcl/bit/bit_field.hpp @@ -0,0 +1,203 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/assert.hpp" +#include "mcl/bitsizeof.hpp" +#include "mcl/concepts/bit_integral.hpp" +#include "mcl/stdint.hpp" + +namespace mcl::bit { + +/// Create a mask with `count` number of one bits. +template +constexpr T ones() { + static_assert(count <= bitsizeof, "count larger than bitsize of T"); + + if constexpr (count == 0) { + return 0; + } else { + return static_cast(~static_cast(0)) >> (bitsizeof - count); + } +} + +/// Create a mask with `count` number of one bits. +template +constexpr T ones(size_t count) { + ASSERT_MSG(count <= bitsizeof, "count larger than bitsize of T"); + + if (count == 0) { + return 0; + } + return ~static_cast(0) >> (bitsizeof - count); +} + +/// Create a mask of type T for bits [begin_bit, end_bit] inclusive. +template +constexpr T mask() { + static_assert(begin_bit <= end_bit, "invalid bit range (position of beginning bit cannot be greater than that of end bit)"); + static_assert(begin_bit < bitsizeof, "begin_bit must be smaller than size of T"); + static_assert(end_bit < bitsizeof, "end_bit must be smaller than size of T"); + + return ones() << begin_bit; +} + +/// Create a mask of type T for bits [begin_bit, end_bit] inclusive. +template +constexpr T mask(size_t begin_bit, size_t end_bit) { + ASSERT_MSG(begin_bit <= end_bit, "invalid bit range (position of beginning bit cannot be greater than that of end bit)"); + ASSERT_MSG(begin_bit < bitsizeof, "begin_bit must be smaller than size of T"); + ASSERT_MSG(end_bit < bitsizeof, "end_bit must be smaller than size of T"); + + return ones(end_bit - begin_bit + 1) << begin_bit; +} + +/// Extract bits [begin_bit, end_bit] inclusive from value of type T. +template +constexpr T get_bits(T value) { + constexpr T m = mask(); + return (value & m) >> begin_bit; +} + +/// Extract bits [begin_bit, end_bit] inclusive from value of type T. +template +constexpr T get_bits(size_t begin_bit, size_t end_bit, T value) { + const T m = mask(begin_bit, end_bit); + return (value & m) >> begin_bit; +} + +/// Clears bits [begin_bit, end_bit] inclusive of value of type T. +template +constexpr T clear_bits(T value) { + constexpr T m = mask(); + return value & ~m; +} + +/// Clears bits [begin_bit, end_bit] inclusive of value of type T. +template +constexpr T clear_bits(size_t begin_bit, size_t end_bit, T value) { + const T m = mask(begin_bit, end_bit); + return value & ~m; +} + +/// Modifies bits [begin_bit, end_bit] inclusive of value of type T. +template +constexpr T set_bits(T value, T new_bits) { + constexpr T m = mask(); + return (value & ~m) | ((new_bits << begin_bit) & m); +} + +/// Modifies bits [begin_bit, end_bit] inclusive of value of type T. +template +constexpr T set_bits(size_t begin_bit, size_t end_bit, T value, T new_bits) { + const T m = mask(begin_bit, end_bit); + return (value & ~m) | ((new_bits << begin_bit) & m); +} + +/// Extract bit at bit_position from value of type T. +template +constexpr bool get_bit(T value) { + constexpr T m = mask(); + return (value & m) != 0; +} + +/// Extract bit at bit_position from value of type T. +template +constexpr bool get_bit(size_t bit_position, T value) { + const T m = mask(bit_position, bit_position); + return (value & m) != 0; +} + +/// Clears bit at bit_position of value of type T. +template +constexpr T clear_bit(T value) { + constexpr T m = mask(); + return value & ~m; +} + +/// Clears bit at bit_position of value of type T. +template +constexpr T clear_bit(size_t bit_position, T value) { + const T m = mask(bit_position, bit_position); + return value & ~m; +} + +/// Modifies bit at bit_position of value of type T. +template +constexpr T set_bit(T value, bool new_bit) { + constexpr T m = mask(); + return (value & ~m) | (new_bit ? m : static_cast(0)); +} + +/// Modifies bit at bit_position of value of type T. +template +constexpr T set_bit(size_t bit_position, T value, bool new_bit) { + const T m = mask(bit_position, bit_position); + return (value & ~m) | (new_bit ? m : static_cast(0)); +} + +/// Sign-extends a value that has bit_count bits to the full bitwidth of type T. +template +constexpr T sign_extend(T value) { + static_assert(bit_count != 0, "cannot sign-extend zero-sized value"); + + constexpr T m = ones(); + if (get_bit(value)) { + return value | ~m; + } + return value; +} + +/// Sign-extends a value that has bit_count bits to the full bitwidth of type T. +template +constexpr T sign_extend(size_t bit_count, T value) { + ASSERT_MSG(bit_count != 0, "cannot sign-extend zero-sized value"); + + const T m = ones(bit_count); + if (get_bit(bit_count - 1, value)) { + return value | ~m; + } + return value; +} + +/// Replicate an element across a value of type T. +template +constexpr T replicate_element(T value) { + static_assert(element_size <= bitsizeof, "element_size is too large"); + static_assert(bitsizeof % element_size == 0, "bitsize of T not divisible by element_size"); + + if constexpr (element_size == bitsizeof) { + return value; + } else { + return replicate_element(static_cast(value | (value << element_size))); + } +} + +/// Replicate an element of type U across a value of type T. +template +constexpr T replicate_element(T value) { + static_assert(bitsizeof <= bitsizeof, "element_size is too large"); + + return replicate_element, T>(value); +} + +/// Replicate an element across a value of type T. +template +constexpr T replicate_element(size_t element_size, T value) { + ASSERT_MSG(element_size <= bitsizeof, "element_size is too large"); + ASSERT_MSG(bitsizeof % element_size == 0, "bitsize of T not divisible by element_size"); + + if (element_size == bitsizeof) { + return value; + } + return replicate_element(static_cast(value | (value << element_size)), element_size * 2); +} + +template +constexpr bool most_significant_bit(T value) { + return get_bit - 1, T>(value); +} + +} // namespace mcl::bit diff --git a/include/mcl/bit/rotate.hpp b/include/mcl/bit/rotate.hpp new file mode 100644 index 00000000..649e5e22 --- /dev/null +++ b/include/mcl/bit/rotate.hpp @@ -0,0 +1,31 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/bitsizeof.hpp" +#include "mcl/concepts/bit_integral.hpp" +#include "mcl/stdint.hpp" + +namespace mcl::bit { + +template +constexpr T rotate_right(T x, size_t amount) { + amount %= bitsizeof; + if (amount == 0) { + return x; + } + return static_cast((x >> amount) | (x << (bitsizeof - amount))); +} + +template +constexpr T rotate_left(T x, size_t amount) { + amount %= bitsizeof; + if (amount == 0) { + return x; + } + return static_cast((x << amount) | (x >> (bitsizeof - amount))); +} + +} // namespace mcl::bit diff --git a/include/mcl/bit/swap.hpp b/include/mcl/bit/swap.hpp new file mode 100644 index 00000000..0df6bac4 --- /dev/null +++ b/include/mcl/bit/swap.hpp @@ -0,0 +1,50 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/concepts/bit_integral.hpp" + +namespace mcl::bit { + +constexpr u16 swap_bytes_16(u16 value) { + return static_cast(u32{value} >> 8 | u32{value} << 8); +} + +constexpr u32 swap_bytes_32(u32 value) { + return ((value & 0xff000000u) >> 24) + | ((value & 0x00ff0000u) >> 8) + | ((value & 0x0000ff00u) << 8) + | ((value & 0x000000ffu) << 24); +} + +constexpr u64 swap_bytes_64(u64 value) { + return ((value & 0xff00000000000000ull) >> 56) + | ((value & 0x00ff000000000000ull) >> 40) + | ((value & 0x0000ff0000000000ull) >> 24) + | ((value & 0x000000ff00000000ull) >> 8) + | ((value & 0x00000000ff000000ull) << 8) + | ((value & 0x0000000000ff0000ull) << 24) + | ((value & 0x000000000000ff00ull) << 40) + | ((value & 0x00000000000000ffull) << 56); +} + +constexpr u32 swap_halves_32(u32 value) { + return ((value & 0xffff0000u) >> 16) + | ((value & 0x0000ffffu) << 16); +} + +constexpr u64 swap_halves_64(u64 value) { + return ((value & 0xffff000000000000ull) >> 48) + | ((value & 0x0000ffff00000000ull) >> 16) + | ((value & 0x00000000ffff0000ull) << 16) + | ((value & 0x000000000000ffffull) << 48); +} + +constexpr u64 swap_words_64(u64 value) { + return ((value & 0xffffffff00000000ull) >> 32) + | ((value & 0x00000000ffffffffull) << 32); +} + +} // namespace mcl::bit diff --git a/include/mcl/bit_cast.hpp b/include/mcl/bit_cast.hpp new file mode 100644 index 00000000..cfa8860a --- /dev/null +++ b/include/mcl/bit_cast.hpp @@ -0,0 +1,36 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +namespace mcl { + +/// Reinterpret objects of one type as another by bit-casting between object representations. +template +inline Dest bit_cast(const Source& source) noexcept { + static_assert(sizeof(Dest) == sizeof(Source), "size of destination and source objects must be equal"); + static_assert(std::is_trivially_copyable_v, "destination type must be trivially copyable."); + static_assert(std::is_trivially_copyable_v, "source type must be trivially copyable"); + + std::aligned_storage_t dest; + std::memcpy(&dest, &source, sizeof(dest)); + return reinterpret_cast(dest); +} + +/// Reinterpret objects of any arbitrary type as another type by bit-casting between object representations. +/// Note that here we do not verify if source pointed to by source_ptr has enough bytes to read from. +template +inline Dest bit_cast_pointee(const SourcePtr source_ptr) noexcept { + static_assert(sizeof(SourcePtr) == sizeof(void*), "source pointer must have size of a pointer"); + static_assert(std::is_trivially_copyable_v, "destination type must be trivially copyable."); + + std::aligned_storage_t dest; + std::memcpy(&dest, bit_cast(source_ptr), sizeof(dest)); + return reinterpret_cast(dest); +} + +} // namespace mcl diff --git a/include/mcl/bitsizeof.hpp b/include/mcl/bitsizeof.hpp new file mode 100644 index 00000000..5d28f595 --- /dev/null +++ b/include/mcl/bitsizeof.hpp @@ -0,0 +1,15 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +namespace mcl { + +template +constexpr std::size_t bitsizeof = CHAR_BIT * sizeof(T); + +} // namespace mcl diff --git a/include/mcl/concepts/bit_integral.hpp b/include/mcl/concepts/bit_integral.hpp new file mode 100644 index 00000000..caddc059 --- /dev/null +++ b/include/mcl/concepts/bit_integral.hpp @@ -0,0 +1,16 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/concepts/is_any_of.hpp" +#include "mcl/stdint.hpp" + +namespace mcl { + +/// Integral upon which bit operations can be safely performed. +template +concept BitIntegral = IsAnyOf; + +} // namespace mcl diff --git a/include/mcl/concepts/is_any_of.hpp b/include/mcl/concepts/is_any_of.hpp new file mode 100644 index 00000000..3e6593db --- /dev/null +++ b/include/mcl/concepts/is_any_of.hpp @@ -0,0 +1,14 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/concepts/same_as.hpp" + +namespace mcl { + +template +concept IsAnyOf = (SameAs || ...); + +} // namespace mcl diff --git a/include/mcl/concepts/same_as.hpp b/include/mcl/concepts/same_as.hpp new file mode 100644 index 00000000..7aaaa501 --- /dev/null +++ b/include/mcl/concepts/same_as.hpp @@ -0,0 +1,19 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +namespace mcl { + +namespace detail { + +template +concept SameHelper = std::is_same_v; + +} // namespace detail + +template +concept SameAs = detail::SameHelper && detail::SameHelper; + +} // namespace mcl diff --git a/include/mcl/container/intrusive_list.hpp b/include/mcl/container/intrusive_list.hpp new file mode 100644 index 00000000..b757f214 --- /dev/null +++ b/include/mcl/container/intrusive_list.hpp @@ -0,0 +1,378 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include +#include + +#include "mcl/assert.hpp" + +namespace mcl { + +template +class intrusive_list; +template +class intrusive_list_iterator; + +template +class intrusive_list_node { +public: + bool is_sentinel() const { + return is_sentinel_; + } + +protected: + intrusive_list_node* next = nullptr; + intrusive_list_node* prev = nullptr; + bool is_sentinel_ = false; + + friend class intrusive_list; + friend class intrusive_list_iterator; + friend class intrusive_list_iterator; +}; + +template +class intrusive_list_sentinel final : public intrusive_list_node { + using intrusive_list_node::next; + using intrusive_list_node::prev; + using intrusive_list_node::is_sentinel_; + +public: + intrusive_list_sentinel() { + next = this; + prev = this; + is_sentinel_ = true; + } +}; + +template +class intrusive_list_iterator { +public: + using iterator_category = std::bidirectional_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + + // If value_type is const, we want "const intrusive_list_node", not "intrusive_list_node" + using node_type = std::conditional_t::value, + const intrusive_list_node>, + intrusive_list_node>; + using node_pointer = node_type*; + using node_reference = node_type&; + + intrusive_list_iterator() = default; + intrusive_list_iterator(const intrusive_list_iterator& other) = default; + intrusive_list_iterator& operator=(const intrusive_list_iterator& other) = default; + + explicit intrusive_list_iterator(node_pointer list_node) + : node(list_node) { + } + explicit intrusive_list_iterator(pointer data) + : node(data) { + } + explicit intrusive_list_iterator(reference data) + : node(&data) { + } + + intrusive_list_iterator& operator++() { + node = node->next; + return *this; + } + intrusive_list_iterator& operator--() { + node = node->prev; + return *this; + } + intrusive_list_iterator operator++(int) { + intrusive_list_iterator it(*this); + ++*this; + return it; + } + intrusive_list_iterator operator--(int) { + intrusive_list_iterator it(*this); + --*this; + return it; + } + + bool operator==(const intrusive_list_iterator& other) const { + return node == other.node; + } + bool operator!=(const intrusive_list_iterator& other) const { + return !operator==(other); + } + + reference operator*() const { + DEBUG_ASSERT(!node->is_sentinel()); + return static_cast(*node); + } + pointer operator->() const { + return std::addressof(operator*()); + } + + node_pointer AsNodePointer() const { + return node; + } + +private: + friend class intrusive_list; + node_pointer node = nullptr; +}; + +template +class intrusive_list { +public: + using difference_type = std::ptrdiff_t; + using size_type = std::size_t; + using value_type = T; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using iterator = intrusive_list_iterator; + using const_iterator = intrusive_list_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + /** + * Inserts a node at the given location indicated by an iterator. + * + * @param location The location to insert the node. + * @param new_node The node to add. + */ + iterator insert(iterator location, pointer new_node) { + return insert_before(location, new_node); + } + + /** + * Inserts a node at the given location, moving the previous + * node occupant ahead of the one inserted. + * + * @param location The location to insert the new node. + * @param new_node The node to insert into the list. + */ + iterator insert_before(iterator location, pointer new_node) { + auto existing_node = location.AsNodePointer(); + + new_node->next = existing_node; + new_node->prev = existing_node->prev; + existing_node->prev->next = new_node; + existing_node->prev = new_node; + + return iterator(new_node); + } + + /** + * Inserts a new node into the list ahead of the position indicated. + * + * @param position Location to insert the node in front of. + * @param new_node The node to be inserted into the list. + */ + iterator insert_after(iterator position, pointer new_node) { + if (empty()) + return insert(begin(), new_node); + + return insert(++position, new_node); + } + + /** + * Add an entry to the start of the list. + * @param node Node to add to the list. + */ + void push_front(pointer node) { + insert(begin(), node); + } + + /** + * Add an entry to the end of the list + * @param node Node to add to the list. + */ + void push_back(pointer node) { + insert(end(), node); + } + + /** + * Erases the node at the front of the list. + * @note Must not be called on an empty list. + */ + void pop_front() { + DEBUG_ASSERT(!empty()); + erase(begin()); + } + + /** + * Erases the node at the back of the list. + * @note Must not be called on an empty list. + */ + void pop_back() { + DEBUG_ASSERT(!empty()); + erase(--end()); + } + + /** + * Removes a node from this list + * @param it An iterator that points to the node to remove from list. + */ + pointer remove(iterator& it) { + DEBUG_ASSERT(it != end()); + + pointer node = &*it++; + + node->prev->next = node->next; + node->next->prev = node->prev; +#if !defined(NDEBUG) + node->next = nullptr; + node->prev = nullptr; +#endif + + return node; + } + + /** + * Removes a node from this list + * @param it A constant iterator that points to the node to remove from list. + */ + pointer remove(const iterator& it) { + iterator copy = it; + return remove(copy); + } + + /** + * Removes a node from this list. + * @param node A pointer to the node to remove. + */ + pointer remove(pointer node) { + return remove(iterator(node)); + } + + /** + * Removes a node from this list. + * @param node A reference to the node to remove. + */ + pointer remove(reference node) { + return remove(iterator(node)); + } + + /** + * Is this list empty? + * @returns true if there are no nodes in this list. + */ + bool empty() const { + return root->next == root.get(); + } + + /** + * Gets the total number of elements within this list. + * @return the number of elements in this list. + */ + size_type size() const { + return static_cast(std::distance(begin(), end())); + } + + /** + * Retrieves a reference to the node at the front of the list. + * @note Must not be called on an empty list. + */ + reference front() { + DEBUG_ASSERT(!empty()); + return *begin(); + } + + /** + * Retrieves a constant reference to the node at the front of the list. + * @note Must not be called on an empty list. + */ + const_reference front() const { + DEBUG_ASSERT(!empty()); + return *begin(); + } + + /** + * Retrieves a reference to the node at the back of the list. + * @note Must not be called on an empty list. + */ + reference back() { + DEBUG_ASSERT(!empty()); + return *--end(); + } + + /** + * Retrieves a constant reference to the node at the back of the list. + * @note Must not be called on an empty list. + */ + const_reference back() const { + DEBUG_ASSERT(!empty()); + return *--end(); + } + + // Iterator interface + iterator begin() { return iterator(root->next); } + const_iterator begin() const { return const_iterator(root->next); } + const_iterator cbegin() const { return begin(); } + + iterator end() { return iterator(root.get()); } + const_iterator end() const { return const_iterator(root.get()); } + const_iterator cend() const { return end(); } + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator crbegin() const { return rbegin(); } + + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + const_reverse_iterator crend() const { return rend(); } + + /** + * Erases a node from the list, indicated by an iterator. + * @param it The iterator that points to the node to erase. + */ + iterator erase(iterator it) { + remove(it); + return it; + } + + /** + * Erases a node from this list. + * @param node A pointer to the node to erase from this list. + */ + iterator erase(pointer node) { + return erase(iterator(node)); + } + + /** + * Erases a node from this list. + * @param node A reference to the node to erase from this list. + */ + iterator erase(reference node) { + return erase(iterator(node)); + } + + /** + * Exchanges contents of this list with another list instance. + * @param other The other list to swap with. + */ + void swap(intrusive_list& other) noexcept { + root.swap(other.root); + } + +private: + std::shared_ptr> root = std::make_shared>(); +}; + +/** + * Exchanges contents of an intrusive list with another intrusive list. + * @tparam T The type of data being kept track of by the lists. + * @param lhs The first list. + * @param rhs The second list. + */ +template +void swap(intrusive_list& lhs, intrusive_list& rhs) noexcept { + lhs.swap(rhs); +} + +} // namespace mcl diff --git a/include/mcl/hint/assume.hpp b/include/mcl/hint/assume.hpp new file mode 100644 index 00000000..ac1873f8 --- /dev/null +++ b/include/mcl/hint/assume.hpp @@ -0,0 +1,13 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#if defined(__clang) || defined(__GNUC__) +# define ASSUME(expr) [&] { if (!(expr)) __builtin_unreachable(); }() +#elif defined(_MSC_VER) +# define ASSUME(expr) __assume(expr) +#else +# define ASSUME(expr) +#endif diff --git a/include/mcl/iterator/reverse.hpp b/include/mcl/iterator/reverse.hpp new file mode 100644 index 00000000..eb21b9e0 --- /dev/null +++ b/include/mcl/iterator/reverse.hpp @@ -0,0 +1,34 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +namespace mcl::iterator { +namespace detail { + +template +struct reverse_adapter { + T& iterable; + + constexpr auto begin() { + using namespace std; + return rbegin(iterable); + } + + constexpr auto end() { + using namespace std; + return rend(iterable); + } +}; + +} // namespace detail + +template +constexpr detail::reverse_adapter reverse(T&& iterable) { + return detail::reverse_adapter{iterable}; +} + +} // namespace mcl::iterator diff --git a/include/mcl/macro/anonymous_variable.hpp b/include/mcl/macro/anonymous_variable.hpp new file mode 100644 index 00000000..09cd48a2 --- /dev/null +++ b/include/mcl/macro/anonymous_variable.hpp @@ -0,0 +1,13 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#ifdef __COUNTER__ +# define ANONYMOUS_VARIABLE(str) CONCATENATE_TOKENS(str, __COUNTER__) +#else +# define ANONYMOUS_VARIABLE(str) CONCATENATE_TOKENS(str, __LINE__) +#endif diff --git a/include/mcl/macro/architecture.hpp b/include/mcl/macro/architecture.hpp new file mode 100644 index 00000000..3251d829 --- /dev/null +++ b/include/mcl/macro/architecture.hpp @@ -0,0 +1,40 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#if defined(__ARM64__) || defined(__aarch64__) || defined(_M_ARM64) +# define MCL_ARCHITECTURE arm64 +# define MCL_ARCHITECTURE_ARM64 1 +#elif defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) +# define MCL_ARCHITECTURE arm32 +# define MCL_ARCHITECTURE_ARM32 1 +#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64) +# define MCL_ARCHITECTURE x86_64 +# define MCL_ARCHITECTURE_X86_64 1 +#elif defined(__i386) || defined(__i386__) || defined(_M_IX86) +# define MCL_ARCHITECTURE x86_32 +# define MCL_ARCHITECTURE_X86_32 1 +#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64) +# define MCL_ARCHITECTURE ia64 +# define MCL_ARCHITECTURE_IA64 1 +#elif defined(__mips) || defined(__mips__) || defined(_M_MRX000) +# define MCL_ARCHITECTURE mips +# define MCL_ARCHITECTURE_MIPS 1 +#elif defined(__ppc64__) || defined(__powerpc64__) +# define MCL_ARCHITECTURE ppc64 +# define MCL_ARCHITECTURE_PPC64 1 +#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) || defined(_M_MPPC) || defined(_M_PPC) +# define MCL_ARCHITECTURE ppc32 +# define MCL_ARCHITECTURE_PPC32 1 +#elif defined(__riscv) +# define MCL_ARCHITECTURE riscv +# define MCL_ARCHITECTURE_RISCV 1 +#elif defined(__EMSCRIPTEN__) +# define MCL_ARCHITECTURE wasm +# define MCL_ARCHITECTURE_WASM 1 +#else +# define MCL_ARCHITECTURE generic +# define MCL_ARCHITECTURE_GENERIC 1 +#endif diff --git a/include/mcl/macro/concatenate_tokens.hpp b/include/mcl/macro/concatenate_tokens.hpp new file mode 100644 index 00000000..3555b23c --- /dev/null +++ b/include/mcl/macro/concatenate_tokens.hpp @@ -0,0 +1,8 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#define CONCATENATE_TOKENS(x, y) CONCATENATE_TOKENS_IMPL(x, y) +#define CONCATENATE_TOKENS_IMPL(x, y) x##y diff --git a/include/mcl/mp/metafunction/apply.hpp b/include/mcl/mp/metafunction/apply.hpp new file mode 100644 index 00000000..e2c17141 --- /dev/null +++ b/include/mcl/mp/metafunction/apply.hpp @@ -0,0 +1,25 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +namespace mcl::mp { + +namespace detail { + +template class F, class L> +struct apply_impl; + +template class F, template class LT, class... Es> +struct apply_impl> { + using type = F; +}; + +} // namespace detail + +/// Invokes metafunction F where the arguments are all the members of list L +template class F, class L> +using apply = typename detail::apply_impl::type; + +} // namespace mcl::mp diff --git a/include/mcl/mp/metafunction/bind.hpp b/include/mcl/mp/metafunction/bind.hpp new file mode 100644 index 00000000..2701fc95 --- /dev/null +++ b/include/mcl/mp/metafunction/bind.hpp @@ -0,0 +1,18 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +namespace mcl::mp { + +/// Binds the first sizeof...(A) arguments of metafunction F with arguments A +template class F, class... As> +struct bind { + template + using type = F; +}; + +} // namespace mcl::mp + +#define MCL_MP_BIND(...) ::mcl::mp::bind<__VA_ARGS__>::template type diff --git a/include/mcl/mp/metafunction/identity.hpp b/include/mcl/mp/metafunction/identity.hpp new file mode 100644 index 00000000..737f9ce1 --- /dev/null +++ b/include/mcl/mp/metafunction/identity.hpp @@ -0,0 +1,22 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +namespace mcl::mp { + +namespace detail { + +template +struct identity_impl { + using type = T; +}; + +} // namespace detail + +/// Identity metafunction +template +using identity = typename identity_impl::type; + +} // namespace mcl::mp diff --git a/include/mcl/mp/metafunction/map.hpp b/include/mcl/mp/metafunction/map.hpp new file mode 100644 index 00000000..13fcaecd --- /dev/null +++ b/include/mcl/mp/metafunction/map.hpp @@ -0,0 +1,25 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +namespace mcl::mp { + +namespace detail { + +template class F, class L> +struct map_impl; + +template class F, template class LT, class... Es> +struct map_impl> { + using type = LT...>; +}; + +} // namespace detail + +/// Applies each element of list L to metafunction F +template class F, class L> +using map = typename detail::map_impl::type; + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/bit_and.hpp b/include/mcl/mp/metavalue/bit_and.hpp new file mode 100644 index 00000000..e4a98e21 --- /dev/null +++ b/include/mcl/mp/metavalue/bit_and.hpp @@ -0,0 +1,19 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/lift_value.hpp" + +namespace mcl::mp { + +/// Bitwise and of metavalues Vs +template +using bit_and = lift_value<(Vs::value & ...)>; + +/// Bitwise and of metavalues Vs +template +constexpr auto bit_and_v = (Vs::value & ...); + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/bit_not.hpp b/include/mcl/mp/metavalue/bit_not.hpp new file mode 100644 index 00000000..5d31956d --- /dev/null +++ b/include/mcl/mp/metavalue/bit_not.hpp @@ -0,0 +1,19 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/lift_value.hpp" + +namespace mcl::mp { + +/// Bitwise not of metavalue V +template +using bit_not = lift_value<~V::value>; + +/// Bitwise not of metavalue V +template +constexpr auto bit_not_v = ~V::value; + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/bit_or.hpp b/include/mcl/mp/metavalue/bit_or.hpp new file mode 100644 index 00000000..812edfb2 --- /dev/null +++ b/include/mcl/mp/metavalue/bit_or.hpp @@ -0,0 +1,19 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/lift_value.hpp" + +namespace mcl::mp { + +/// Bitwise or of metavalues Vs +template +using bit_or = lift_value<(Vs::value | ...)>; + +/// Bitwise or of metavalues Vs +template +constexpr auto bit_or_v = (Vs::value | ...); + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/bit_xor.hpp b/include/mcl/mp/metavalue/bit_xor.hpp new file mode 100644 index 00000000..9c543d41 --- /dev/null +++ b/include/mcl/mp/metavalue/bit_xor.hpp @@ -0,0 +1,19 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/lift_value.hpp" + +namespace mcl::mp { + +/// Bitwise xor of metavalues Vs +template +using bit_xor = lift_value<(Vs::value ^ ...)>; + +/// Bitwise xor of metavalues Vs +template +constexpr auto bit_xor_v = (Vs::value ^ ...); + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/conjunction.hpp b/include/mcl/mp/metavalue/conjunction.hpp new file mode 100644 index 00000000..71a8f67a --- /dev/null +++ b/include/mcl/mp/metavalue/conjunction.hpp @@ -0,0 +1,42 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/logic_if.hpp" +#include "mcl/mp/metavalue/value.hpp" + +namespace mcl::mp { + +namespace detail { + +template +struct conjunction_impl; + +template<> +struct conjunction_impl<> { + using type = false_type; +}; + +template +struct conjunction_impl { + using type = V; +}; + +template +struct conjunction_impl { + using type = logic_if::type, V1>; +}; + +} // namespace detail + +/// Conjunction of metavalues Vs with short-circuiting and type preservation. +template +using conjunction = typename detail::conjunction_impl::type; + +/// Conjunction of metavalues Vs with short-circuiting and type preservation. +template +constexpr auto conjunction_v = conjunction::value; + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/disjunction.hpp b/include/mcl/mp/metavalue/disjunction.hpp new file mode 100644 index 00000000..679a44f4 --- /dev/null +++ b/include/mcl/mp/metavalue/disjunction.hpp @@ -0,0 +1,42 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/logic_if.hpp" +#include "mcl/mp/metavalue/value.hpp" + +namespace mcl::mp { + +namespace detail { + +template +struct disjunction_impl; + +template<> +struct disjunction_impl<> { + using type = false_type; +}; + +template +struct disjunction_impl { + using type = V; +}; + +template +struct disjunction_impl { + using type = logic_if::type>; +}; + +} // namespace detail + +/// Disjunction of metavalues Vs with short-circuiting and type preservation. +template +using disjunction = typename detail::disjunction_impl::type; + +/// Disjunction of metavalues Vs with short-circuiting and type preservation. +template +constexpr auto disjunction_v = disjunction::value; + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/lift_value.hpp b/include/mcl/mp/metavalue/lift_value.hpp new file mode 100644 index 00000000..bd5df322 --- /dev/null +++ b/include/mcl/mp/metavalue/lift_value.hpp @@ -0,0 +1,15 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +namespace mcl::mp { + +/// Lifts a value into a type (a metavalue) +template +using lift_value = std::integral_constant; + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/logic_and.hpp b/include/mcl/mp/metavalue/logic_and.hpp new file mode 100644 index 00000000..81c40a45 --- /dev/null +++ b/include/mcl/mp/metavalue/logic_and.hpp @@ -0,0 +1,19 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/value.hpp" + +namespace mcl::mp { + +/// Logical conjunction of metavalues Vs without short-circuiting or type presevation. +template +using logic_and = bool_value<(true && ... && Vs::value)>; + +/// Logical conjunction of metavalues Vs without short-circuiting or type presevation. +template +constexpr bool logic_and_v = (true && ... && Vs::value); + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/logic_if.hpp b/include/mcl/mp/metavalue/logic_if.hpp new file mode 100644 index 00000000..b300d267 --- /dev/null +++ b/include/mcl/mp/metavalue/logic_if.hpp @@ -0,0 +1,21 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "mcl/mp/metavalue/value.hpp" + +namespace mcl::mp { + +/// Conditionally select between types T and F based on boolean metavalue V +template +using logic_if = std::conditional_t; + +/// Conditionally select between metavalues T and F based on boolean metavalue V +template +constexpr auto logic_if_v = logic_if::value; + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/logic_not.hpp b/include/mcl/mp/metavalue/logic_not.hpp new file mode 100644 index 00000000..a7a6aee9 --- /dev/null +++ b/include/mcl/mp/metavalue/logic_not.hpp @@ -0,0 +1,19 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/value.hpp" + +namespace mcl::mp { + +/// Logical negation of metavalue V. +template +using logic_not = bool_value; + +/// Logical negation of metavalue V. +template +constexpr bool logic_not_v = !bool(V::value); + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/logic_or.hpp b/include/mcl/mp/metavalue/logic_or.hpp new file mode 100644 index 00000000..3b46fa57 --- /dev/null +++ b/include/mcl/mp/metavalue/logic_or.hpp @@ -0,0 +1,19 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/value.hpp" + +namespace mcl::mp { + +/// Logical disjunction of metavalues Vs without short-circuiting or type presevation. +template +using logic_or = bool_value<(false || ... || Vs::value)>; + +/// Logical disjunction of metavalues Vs without short-circuiting or type presevation. +template +constexpr bool logic_or_v = (false || ... || Vs::value); + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/product.hpp b/include/mcl/mp/metavalue/product.hpp new file mode 100644 index 00000000..d40c0ce3 --- /dev/null +++ b/include/mcl/mp/metavalue/product.hpp @@ -0,0 +1,19 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/lift_value.hpp" + +namespace mcl::mp { + +/// Product of metavalues Vs +template +using product = lift_value<(Vs::value * ...)>; + +/// Product of metavalues Vs +template +constexpr auto product_v = (Vs::value * ...); + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/sum.hpp b/include/mcl/mp/metavalue/sum.hpp new file mode 100644 index 00000000..7111c02c --- /dev/null +++ b/include/mcl/mp/metavalue/sum.hpp @@ -0,0 +1,19 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/lift_value.hpp" + +namespace mcl::mp { + +/// Sum of metavalues Vs +template +using sum = lift_value<(Vs::value + ...)>; + +/// Sum of metavalues Vs +template +constexpr auto sum_v = (Vs::value + ...); + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/value.hpp b/include/mcl/mp/metavalue/value.hpp new file mode 100644 index 00000000..693169d6 --- /dev/null +++ b/include/mcl/mp/metavalue/value.hpp @@ -0,0 +1,30 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +namespace mcl::mp { + +/// A metavalue (of type VT and value v). +template +using value = std::integral_constant; + +/// A metavalue of type size_t (and value v). +template +using size_value = value; + +/// A metavalue of type bool (and value v). (Aliases to std::bool_constant.) +template +using bool_value = value; + +/// true metavalue (Aliases to std::true_type). +using true_type = bool_value; + +/// false metavalue (Aliases to std::false_type). +using false_type = bool_value; + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/value_cast.hpp b/include/mcl/mp/metavalue/value_cast.hpp new file mode 100644 index 00000000..3b88ed7d --- /dev/null +++ b/include/mcl/mp/metavalue/value_cast.hpp @@ -0,0 +1,15 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +namespace mcl::mp { + +/// Casts a metavalue from one type to another +template +using value_cast = std::integral_constant(V::value)>; + +} // namespace mcl::mp diff --git a/include/mcl/mp/metavalue/value_equal.hpp b/include/mcl/mp/metavalue/value_equal.hpp new file mode 100644 index 00000000..a10e07f0 --- /dev/null +++ b/include/mcl/mp/metavalue/value_equal.hpp @@ -0,0 +1,15 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +namespace mcl::mp { + +/// Do two metavalues contain the same value? +template +using value_equal = std::bool_constant; + +} // namespace mcl::mp diff --git a/include/mcl/mp/misc/argument_count.hpp b/include/mcl/mp/misc/argument_count.hpp new file mode 100644 index 00000000..5a30f498 --- /dev/null +++ b/include/mcl/mp/misc/argument_count.hpp @@ -0,0 +1,19 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/lift_value.hpp" + +namespace mcl::mp { + +/// Metafunction that returns the number of arguments it has +template +using argument_count = lift_value; + +/// Metafunction that returns the number of arguments it has +template +constexpr auto argument_count_v = sizeof...(Ts); + +} // namespace mcl::mp diff --git a/include/mcl/mp/typelist/append.hpp b/include/mcl/mp/typelist/append.hpp new file mode 100644 index 00000000..838b9c94 --- /dev/null +++ b/include/mcl/mp/typelist/append.hpp @@ -0,0 +1,25 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +namespace mcl::mp { + +namespace detail { + +template +struct append_impl; + +template class LT, class... E1s, class... E2s> +struct append_impl, E2s...> { + using type = LT; +}; + +} // namespace detail + +/// Append items E to list L +template +using append = typename detail::append_impl::type; + +} // namespace mcl::mp diff --git a/include/mcl/mp/typelist/cartesian_product.hpp b/include/mcl/mp/typelist/cartesian_product.hpp new file mode 100644 index 00000000..1b378c6f --- /dev/null +++ b/include/mcl/mp/typelist/cartesian_product.hpp @@ -0,0 +1,47 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metafunction/bind.hpp" +#include "mcl/mp/metafunction/map.hpp" +#include "mcl/mp/typelist/append.hpp" +#include "mcl/mp/typelist/concat.hpp" +#include "mcl/mp/typelist/list.hpp" + +namespace mcl::mp { + +namespace detail { + +template +struct cartesian_product_impl; + +template +struct cartesian_product_impl { + using type = RL; +}; + +template class LT, class... REs, class... E2s> +struct cartesian_product_impl, LT> { + using type = concat< + map>...>; +}; + +template +struct cartesian_product_impl { + using type = typename cartesian_product_impl< + typename cartesian_product_impl::type, + L3, + Ls...>::type; +}; + +} // namespace detail + +/// Produces the cartesian product of a set of lists +/// For example: +/// cartesian_product, list> == list, list, list, list +template +using cartesian_product = typename detail::cartesian_product_impl, Ls...>::type; + +} // namespace mcl::mp diff --git a/include/mcl/mp/typelist/concat.hpp b/include/mcl/mp/typelist/concat.hpp new file mode 100644 index 00000000..cfdefbc1 --- /dev/null +++ b/include/mcl/mp/typelist/concat.hpp @@ -0,0 +1,94 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/typelist/list.hpp" + +namespace mcl::mp { + +namespace detail { + +template +struct concat_impl; + +template<> +struct concat_impl<> { + using type = list<>; +}; + +template +struct concat_impl { + using type = L; +}; + +template class LT, class... E1s, class... E2s, class... Ls> +struct concat_impl, LT, Ls...> { + using type = typename concat_impl, Ls...>::type; +}; + +template class LT, + class... E1s, + class... E2s, + class... E3s, + class... E4s, + class... E5s, + class... E6s, + class... E7s, + class... E8s, + class... E9s, + class... E10s, + class... E11s, + class... E12s, + class... E13s, + class... E14s, + class... E15s, + class... E16s, + class... Ls> +struct concat_impl< + LT, + LT, + LT, + LT, + LT, + LT, + LT, + LT, + LT, + LT, + LT, + LT, + LT, + LT, + LT, + LT, + Ls...> { + using type = typename concat_impl< + LT< + E1s..., + E2s..., + E3s..., + E4s..., + E5s..., + E6s..., + E7s..., + E8s..., + E9s..., + E10s..., + E11s..., + E12s..., + E13s..., + E14s..., + E15s..., + E16s...>, + Ls...>::type; +}; + +} // namespace detail + +/// Concatenate lists together +template +using concat = typename detail::concat_impl::type; + +} // namespace mcl::mp diff --git a/include/mcl/mp/typelist/contains.hpp b/include/mcl/mp/typelist/contains.hpp new file mode 100644 index 00000000..f8d1fbf8 --- /dev/null +++ b/include/mcl/mp/typelist/contains.hpp @@ -0,0 +1,23 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/value.hpp" + +namespace mcl::mp { + +/// Does list L contain an element which is same as type T? +template +struct contains; + +template class LT, class... Ts, class T> +struct contains, T> + : bool_value<(false || ... || std::is_same_v)> {}; + +/// Does list L contain an element which is same as type T? +template +constexpr bool contains_v = contains::value; + +} // namespace mcl::mp diff --git a/include/mcl/mp/typelist/drop.hpp b/include/mcl/mp/typelist/drop.hpp new file mode 100644 index 00000000..9c7be44b --- /dev/null +++ b/include/mcl/mp/typelist/drop.hpp @@ -0,0 +1,33 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +namespace mcl::mp { + +namespace detail { + +template +struct drop_impl; + +template class LT> +struct drop_impl> { + using type = LT<>; +}; + +template class LT, class E1, class... Es> +struct drop_impl> { + using type = std::conditional_t, typename drop_impl>::type>; +}; + +} // namespace detail + +/// Drops the first N elements of list L +template +using drop = typename detail::drop_impl::type; + +} // namespace mcl::mp diff --git a/include/mcl/mp/typelist/get.hpp b/include/mcl/mp/typelist/get.hpp new file mode 100644 index 00000000..a2ec7461 --- /dev/null +++ b/include/mcl/mp/typelist/get.hpp @@ -0,0 +1,18 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "mcl/mp/metafunction/apply.hpp" + +namespace mcl::mp { + +/// Get element I from list L +template +using get = std::tuple_element_t>; + +} // namespace mcl::mp diff --git a/include/mcl/mp/typelist/head.hpp b/include/mcl/mp/typelist/head.hpp new file mode 100644 index 00000000..63062825 --- /dev/null +++ b/include/mcl/mp/typelist/head.hpp @@ -0,0 +1,25 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +namespace mcl::mp { + +namespace detail { + +template +struct head_impl; + +template class LT, class E1, class... Es> +struct head_impl> { + using type = E1; +}; + +} // namespace detail + +/// Gets the tail/cdr/all-but-the-first-element of list L +template +using head = typename detail::head_impl::type; + +} // namespace mcl::mp diff --git a/include/mcl/mp/typelist/length.hpp b/include/mcl/mp/typelist/length.hpp new file mode 100644 index 00000000..d5949604 --- /dev/null +++ b/include/mcl/mp/typelist/length.hpp @@ -0,0 +1,20 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metafunction/apply.hpp" +#include "mcl/mp/misc/argument_count.hpp" + +namespace mcl::mp { + +/// Length of list L +template +using length = apply; + +/// Length of list L +template +constexpr auto length_v = length::value; + +} // namespace mcl::mp diff --git a/include/mcl/mp/typelist/lift_sequence.hpp b/include/mcl/mp/typelist/lift_sequence.hpp new file mode 100644 index 00000000..ba2617b8 --- /dev/null +++ b/include/mcl/mp/typelist/lift_sequence.hpp @@ -0,0 +1,29 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "mcl/mp/typelist/list.hpp" + +namespace mcl::mp { + +namespace detail { + +template +struct lift_sequence_impl; + +template class VLT, T... values> +struct lift_sequence_impl> { + using type = list...>; +}; + +} // namespace detail + +/// Lifts values in value list VL to create a type list. +template +using lift_sequence = typename detail::lift_sequence_impl::type; + +} // namespace mcl::mp diff --git a/include/mcl/mp/typelist/list.hpp b/include/mcl/mp/typelist/list.hpp new file mode 100644 index 00000000..48348ec7 --- /dev/null +++ b/include/mcl/mp/typelist/list.hpp @@ -0,0 +1,13 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +namespace mcl::mp { + +/// Contains a list of types +template +struct list {}; + +} // namespace mcl::mp diff --git a/include/mcl/mp/typelist/lower_to_tuple.hpp b/include/mcl/mp/typelist/lower_to_tuple.hpp new file mode 100644 index 00000000..a9007f3b --- /dev/null +++ b/include/mcl/mp/typelist/lower_to_tuple.hpp @@ -0,0 +1,24 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +namespace mcl::mp { + +/// Converts a list of metavalues to a tuple. +template +struct lower_to_tuple; + +template class LT, class... Es> +struct lower_to_tuple> { + static constexpr auto value = std::make_tuple(static_cast(Es::value)...); +}; + +/// Converts a list of metavalues to a tuple. +template +constexpr auto lower_to_tuple_v = lower_to_tuple::value; + +} // namespace mcl::mp diff --git a/include/mcl/mp/typelist/prepend.hpp b/include/mcl/mp/typelist/prepend.hpp new file mode 100644 index 00000000..df9aedd8 --- /dev/null +++ b/include/mcl/mp/typelist/prepend.hpp @@ -0,0 +1,25 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +namespace mcl::mp { + +namespace detail { + +template +struct prepend_impl; + +template class LT, class... E1s, class... E2s> +struct prepend_impl, E2s...> { + using type = LT; +}; + +} // namespace detail + +/// Prepend items E to list L +template +using prepend = typename detail::prepend_impl::type; + +} // namespace mcl::mp diff --git a/include/mcl/mp/typelist/tail.hpp b/include/mcl/mp/typelist/tail.hpp new file mode 100644 index 00000000..54f14c12 --- /dev/null +++ b/include/mcl/mp/typelist/tail.hpp @@ -0,0 +1,25 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +namespace mcl::mp { + +namespace detail { + +template +struct tail_impl; + +template class LT, class E1, class... Es> +struct tail_impl> { + using type = LT; +}; + +} // namespace detail + +/// Gets the first type of list L +template +using tail = typename detail::tail_impl::type; + +} // namespace mcl::mp diff --git a/include/mcl/scope_exit.hpp b/include/mcl/scope_exit.hpp new file mode 100644 index 00000000..d6d11ed2 --- /dev/null +++ b/include/mcl/scope_exit.hpp @@ -0,0 +1,85 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include + +#include + +namespace mcl::detail { + +struct scope_exit_tag {}; +struct scope_fail_tag {}; +struct scope_success_tag {}; + +template +class scope_exit final { +public: + explicit scope_exit(Function&& fn) + : function(std::move(fn)) {} + ~scope_exit() noexcept { + function(); + } + +private: + Function function; +}; + +template +class scope_fail final { +public: + explicit scope_fail(Function&& fn) + : function(std::move(fn)), exception_count(std::uncaught_exceptions()) {} + ~scope_fail() noexcept { + if (std::uncaught_exceptions() > exception_count) { + function(); + } + } + +private: + Function function; + int exception_count; +}; + +template +class scope_success final { +public: + explicit scope_success(Function&& fn) + : function(std::move(fn)), exception_count(std::uncaught_exceptions()) {} + ~scope_success() { + if (std::uncaught_exceptions() <= exception_count) { + function(); + } + } + +private: + Function function; + int exception_count; +}; + +// We use ->* here as it has the highest precedence of the operators we can use. + +template +auto operator->*(scope_exit_tag, Function&& function) { + return scope_exit>{std::forward(function)}; +} + +template +auto operator->*(scope_fail_tag, Function&& function) { + return scope_fail>{std::forward(function)}; +} + +template +auto operator->*(scope_success_tag, Function&& function) { + return scope_success>{std::forward(function)}; +} + +} // namespace mcl::detail + +#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(MCL_SCOPE_EXIT_VAR_) = ::mcl::detail::scope_exit_tag{}->*[&]() noexcept +#define SCOPE_FAIL auto ANONYMOUS_VARIABLE(MCL_SCOPE_FAIL_VAR_) = ::mcl::detail::scope_fail_tag{}->*[&]() noexcept +#define SCOPE_SUCCESS auto ANONYMOUS_VARIABLE(MCL_SCOPE_FAIL_VAR_) = ::mcl::detail::scope_success_tag{}->*[&]() diff --git a/include/mcl/stdint.hpp b/include/mcl/stdint.hpp new file mode 100644 index 00000000..37b82a2b --- /dev/null +++ b/include/mcl/stdint.hpp @@ -0,0 +1,27 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +using u8 = std::uint8_t; +using u16 = std::uint16_t; +using u32 = std::uint32_t; +using u64 = std::uint64_t; +using uptr = std::uintptr_t; + +using s8 = std::int8_t; +using s16 = std::int16_t; +using s32 = std::int32_t; +using s64 = std::int64_t; +using sptr = std::intptr_t; + +using size_t = std::size_t; + +using f32 = float; +using f64 = double; +static_assert(sizeof(f32) == sizeof(u32), "f32 must be 32 bits wide"); +static_assert(sizeof(f64) == sizeof(u64), "f64 must be 64 bits wide"); diff --git a/include/mcl/type_traits/function_info.hpp b/include/mcl/type_traits/function_info.hpp new file mode 100644 index 00000000..2ac804ae --- /dev/null +++ b/include/mcl/type_traits/function_info.hpp @@ -0,0 +1,70 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "mcl/mp/typelist/list.hpp" + +namespace mcl { + +template +struct function_info : function_info {}; + +template +struct function_info { + using return_type = R; + using parameter_list = mp::list; + static constexpr std::size_t parameter_count = sizeof...(As); + + using equivalent_function_type = R(As...); + + template + struct parameter { + static_assert(I < parameter_count, "Non-existent parameter"); + using type = std::tuple_element_t>; + }; +}; + +template +struct function_info : function_info {}; + +template +struct function_info : function_info { + using class_type = C; + + using equivalent_function_type_with_class = R(C*, As...); +}; + +template +struct function_info : function_info { + using class_type = C; + + using equivalent_function_type_with_class = R(C*, As...); +}; + +template +constexpr size_t parameter_count_v = function_info::parameter_count; + +template +using parameter_list = typename function_info::parameter_list; + +template +using get_parameter = typename function_info::template parameter::type; + +template +using equivalent_function_type = typename function_info::equivalent_function_type; + +template +using equivalent_function_type_with_class = typename function_info::equivalent_function_type_with_class; + +template +using return_type = typename function_info::return_type; + +template +using class_type = typename function_info::class_type; + +} // namespace mcl diff --git a/include/mcl/type_traits/integer_of_size.hpp b/include/mcl/type_traits/integer_of_size.hpp new file mode 100644 index 00000000..e37995ea --- /dev/null +++ b/include/mcl/type_traits/integer_of_size.hpp @@ -0,0 +1,48 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/stdint.hpp" + +namespace mcl { + +namespace detail { + +template +struct integer_of_size_impl {}; + +template<> +struct integer_of_size_impl<8> { + using unsigned_type = u8; + using signed_type = s8; +}; + +template<> +struct integer_of_size_impl<16> { + using unsigned_type = u16; + using signed_type = s16; +}; + +template<> +struct integer_of_size_impl<32> { + using unsigned_type = u32; + using signed_type = s32; +}; + +template<> +struct integer_of_size_impl<64> { + using unsigned_type = u64; + using signed_type = s64; +}; + +} // namespace detail + +template +using unsigned_integer_of_size = typename detail::integer_of_size_impl::unsigned_type; + +template +using signed_integer_of_size = typename detail::integer_of_size_impl::signed_type; + +} // namespace mcl diff --git a/include/mcl/type_traits/is_instance_of_template.hpp b/include/mcl/type_traits/is_instance_of_template.hpp new file mode 100644 index 00000000..8a7fc33a --- /dev/null +++ b/include/mcl/type_traits/is_instance_of_template.hpp @@ -0,0 +1,22 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "mcl/mp/metavalue/value.hpp" + +namespace mcl { + +/// Is type T an instance of template class C? +template class, class> +struct is_instance_of_template : mp::false_type {}; + +template class C, class... As> +struct is_instance_of_template> : mp::true_type {}; + +/// Is type T an instance of template class C? +template class C, class T> +constexpr bool is_instance_of_template_v = is_instance_of_template::value; + +} // namespace mcl diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..a25392b3 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,69 @@ +add_library(mcl + ../include/mcl/assert.hpp + ../include/mcl/bit/bit_count.hpp + ../include/mcl/bit/bit_field.hpp + ../include/mcl/bit/rotate.hpp + ../include/mcl/bit/swap.hpp + ../include/mcl/bit_cast.hpp + ../include/mcl/bitsizeof.hpp + ../include/mcl/concepts/bit_integral.hpp + ../include/mcl/concepts/is_any_of.hpp + ../include/mcl/concepts/same_as.hpp + ../include/mcl/container/intrusive_list.hpp + ../include/mcl/hint/assume.hpp + ../include/mcl/iterator/reverse.hpp + ../include/mcl/macro/anonymous_variable.hpp + ../include/mcl/macro/architecture.hpp + ../include/mcl/macro/concatenate_tokens.hpp + ../include/mcl/mp/metafunction/apply.hpp + ../include/mcl/mp/metafunction/bind.hpp + ../include/mcl/mp/metafunction/identity.hpp + ../include/mcl/mp/metafunction/map.hpp + ../include/mcl/mp/metavalue/bit_and.hpp + ../include/mcl/mp/metavalue/bit_not.hpp + ../include/mcl/mp/metavalue/bit_or.hpp + ../include/mcl/mp/metavalue/bit_xor.hpp + ../include/mcl/mp/metavalue/conjunction.hpp + ../include/mcl/mp/metavalue/disjunction.hpp + ../include/mcl/mp/metavalue/lift_value.hpp + ../include/mcl/mp/metavalue/logic_and.hpp + ../include/mcl/mp/metavalue/logic_if.hpp + ../include/mcl/mp/metavalue/logic_not.hpp + ../include/mcl/mp/metavalue/logic_or.hpp + ../include/mcl/mp/metavalue/product.hpp + ../include/mcl/mp/metavalue/sum.hpp + ../include/mcl/mp/metavalue/value.hpp + ../include/mcl/mp/metavalue/value_cast.hpp + ../include/mcl/mp/metavalue/value_equal.hpp + ../include/mcl/mp/misc/argument_count.hpp + ../include/mcl/mp/typelist/append.hpp + ../include/mcl/mp/typelist/cartesian_product.hpp + ../include/mcl/mp/typelist/concat.hpp + ../include/mcl/mp/typelist/contains.hpp + ../include/mcl/mp/typelist/drop.hpp + ../include/mcl/mp/typelist/get.hpp + ../include/mcl/mp/typelist/head.hpp + ../include/mcl/mp/typelist/length.hpp + ../include/mcl/mp/typelist/lift_sequence.hpp + ../include/mcl/mp/typelist/list.hpp + ../include/mcl/mp/typelist/lower_to_tuple.hpp + ../include/mcl/mp/typelist/prepend.hpp + ../include/mcl/mp/typelist/tail.hpp + ../include/mcl/scope_exit.hpp + ../include/mcl/stdint.hpp + ../include/mcl/type_traits/function_info.hpp + ../include/mcl/type_traits/integer_of_size.hpp + ../include/mcl/type_traits/is_instance_of_template.hpp + assert.cpp +) +target_include_directories(mcl + PUBLIC + $ + $ +) +target_compile_options(mcl PRIVATE ${MCL_CXX_FLAGS}) +target_link_libraries(mcl PUBLIC $) +add_library(merry::mcl ALIAS mcl) + +include(CreateTargetDirectoryGroups) +create_target_directory_groups(mcl) diff --git a/src/assert.cpp b/src/assert.cpp new file mode 100644 index 00000000..e30697e2 --- /dev/null +++ b/src/assert.cpp @@ -0,0 +1,20 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#include "mcl/assert.hpp" + +#include +#include + +#include + +namespace mcl::detail { + +[[noreturn]] void assert_terminate_impl(fmt::string_view msg, fmt::format_args args) { + fmt::print(stderr, "assertion failed: "); + fmt::vprint(stderr, msg, args); + std::terminate(); +} + +} // namespace mcl::detail diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 00000000..1b60518d --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,14 @@ +add_executable(mcl-tests + main.cpp + mp/metavalue_tests.cpp + mp/typelist_tests.cpp + type_traits/type_traits_tests.cpp +) +target_include_directories(mcl-tests PUBLIC .) +target_compile_options(mcl-tests PRIVATE ${STAMINA_CXX_FLAGS}) +target_link_libraries(mcl-tests PRIVATE Catch2::Catch2 mcl) + +include(CTest) +include(Catch) +catch_discover_tests(mcl-tests) +enable_testing() diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 00000000..14b471b4 --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,6 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#define CATCH_CONFIG_MAIN +#include "catch2/catch.hpp" diff --git a/tests/mp/metavalue_tests.cpp b/tests/mp/metavalue_tests.cpp new file mode 100644 index 00000000..b7d763dc --- /dev/null +++ b/tests/mp/metavalue_tests.cpp @@ -0,0 +1,90 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace mcl::mp; + +// bit_and + +static_assert(bit_and, lift_value<1>>::value == 1); + +// bit_not + +static_assert(bit_not>::value == ~0); + +// bit_or + +static_assert(bit_or, lift_value<3>>::value == 3); + +// bit_xor + +static_assert(bit_xor, lift_value<3>>::value == 2); + +// conjunction + +static_assert(std::is_same_v, std::true_type>); +static_assert(std::is_same_v>, lift_value<0>>); +static_assert(std::is_same_v, std::true_type>, std::true_type>); + +// disjunction + +static_assert(std::is_same_v, std::true_type>); +static_assert(std::is_same_v>, lift_value<0>>); +static_assert(std::is_same_v, std::true_type>, lift_value<42>>); + +// lift_value + +static_assert(std::is_same_v, std::integral_constant>); +static_assert(std::is_same_v, std::false_type>); + +// logic_and + +static_assert(std::is_same_v, std::true_type>); +static_assert(std::is_same_v, std::true_type>); +static_assert(std::is_same_v>, std::true_type>); +static_assert(std::is_same_v, std::false_type>); + +// logic_not + +static_assert(std::is_same_v, std::true_type>); + +// logic_or + +static_assert(std::is_same_v, std::false_type>); +static_assert(std::is_same_v, std::true_type>); +static_assert(std::is_same_v>, std::false_type>); +static_assert(std::is_same_v, std::true_type>); + +// product + +static_assert(product, lift_value<2>, lift_value<3>, lift_value<4>>::value == 24); + +// sum + +static_assert(sum, lift_value<2>, lift_value<3>, lift_value<4>>::value == 10); + +// value_cast + +static_assert(std::is_same_v, std::integral_constant>); + +// value_equal + +static_assert(std::is_same_v>, std::true_type>); diff --git a/tests/mp/typelist_tests.cpp b/tests/mp/typelist_tests.cpp new file mode 100644 index 00000000..4f67dc4e --- /dev/null +++ b/tests/mp/typelist_tests.cpp @@ -0,0 +1,104 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace mcl::mp; + +// append + +static_assert(std::is_same_v, double>, list>); +static_assert(std::is_same_v, int, int>, list>); + +// cartesian_product + +static_assert( + std::is_same_v< + cartesian_product, list, list>, + list< + list, + list, + list, + list, + list, + list, + list, + list>>); + +// concat + +static_assert(std::is_same_v, list>, list>); +static_assert(std::is_same_v, list, list>, list>); + +// contains + +static_assert(contains_v, int>); +static_assert(!contains_v, int>); +static_assert(!contains_v, int>); +static_assert(contains_v, int>); + +// drop + +static_assert(std::is_same_v, drop<3, list>>); +static_assert(std::is_same_v, drop<3, list>>); +static_assert(std::is_same_v, drop<3, list>>); +static_assert(std::is_same_v, drop<3, list>>); +static_assert(std::is_same_v, drop<0, list>>); + +// get + +static_assert(std::is_same_v>, int>); +static_assert(std::is_same_v>, double>); + +// head + +static_assert(std::is_same_v>, int>); +static_assert(std::is_same_v>, int>); + +// length + +static_assert(length_v> == 0); +static_assert(length_v> == 1); +static_assert(length_v> == 3); + +// lift_sequence + +static_assert( + std::is_same_v< + lift_sequence>, + list, size_value<1>, size_value<2>>>); + +// lower_to_tuple + +static_assert(lower_to_tuple_v, size_value<1>, size_value<2>>> == std::tuple(0, 1, 2)); +static_assert(lower_to_tuple_v> == std::make_tuple(true, false)); + +// prepend + +static_assert(std::is_same_v, double>, list>); +static_assert(std::is_same_v, double>, list>); +static_assert(std::is_same_v, double, bool>, list>); + +// tail + +static_assert(std::is_same_v>, list>); +static_assert(std::is_same_v>, list<>>); diff --git a/tests/type_traits/type_traits_tests.cpp b/tests/type_traits/type_traits_tests.cpp new file mode 100644 index 00000000..b1a3ed7a --- /dev/null +++ b/tests/type_traits/type_traits_tests.cpp @@ -0,0 +1,39 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#include +#include + +#include +#include + +using namespace mcl; + +// function_info + +struct Bar { + int frob(double a) { return a; } +}; + +static_assert(parameter_count_v == 0); +static_assert(parameter_count_v == 3); +static_assert(std::is_same_v, double>); +static_assert(std::is_same_v, void(bool, int, double)>); +static_assert(std::is_same_v, void>); +static_assert(std::is_same_v, int(double)>); +static_assert(std::is_same_v, Bar>); + +// is_instance_of_template + +template +class Foo {}; + +template +class Pair {}; + +static_assert(is_instance_of_template_v>); +static_assert(!is_instance_of_template_v); +static_assert(is_instance_of_template_v>); +static_assert(is_instance_of_template_v>); +static_assert(!is_instance_of_template_v>);