From af9318fea06ec32884c18aac8c3834c0d214834a Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 21 Dec 2018 18:32:40 -0800 Subject: [PATCH] Merge the three streams of meta: * meta * range-v3 * cmcstl2 Details: * Modernize cmake a bit, add support for MSVC/clang-cl. * Update CI config from range-v3, add MSVC to appveyor. * C++20-ify requires-clauses. * Armor `Integral` concept against non-constant expressions. * Don't constraint all arguments of the concept implementations of `and_`, `or_`, which causes instantation defeating the short-circuiting. * Implement `and_v` and `or_v` variable template forms of `and_c` and `or_c`. * `detail::count_`: remove unused third template parameter. * Remove `inline v1` namespace. --- .travis.yml | 109 +- CMakeLists.txt | 47 +- appveyor.yml | 51 + example/CMakeLists.txt | 6 +- include/meta/meta.hpp | 6191 ++++++++++++++++++++----------------- include/meta/meta_fwd.hpp | 278 +- install_libcxx.sh | 18 +- test/CMakeLists.txt | 5 +- test/meta.cpp | 21 + 9 files changed, 3764 insertions(+), 2962 deletions(-) create mode 100644 appveyor.yml diff --git a/.travis.yml b/.travis.yml index 17ac415..3019bfc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,11 +13,20 @@ # - Louis Dionne's Hana: https://github.com/ldionne/hana # - Paul Fultz II's FIT: https://github.com/pfultz2/Fit language: cpp +sudo: required script: cmake +git: + depth: 1 + +env: + global: + - DEPS_DIR=${TRAVIS_BUILD_DIR}/deps + - CMAKE_VERSION="3.6.3" + cache: directories: - - ${TRAVIS_BUILD_DIR}/deps/cmake + - ${DEPS_DIR}/cmake-${CMAKE_VERSION} matrix: include: @@ -25,25 +34,22 @@ matrix: os: osx compiler: clang - # ASAN disabled for clang < 5 builds per resolution of - # https://llvm.org/bugs/show_bug.cgi?id=22757 - + # clang 3.6 C++11/14 Release libc++ - env: CLANG_VERSION=3.6 BUILD_TYPE=Release CPP=11 LIBCXX=On os: linux addons: &clang36 apt: packages: - - util-linux - clang-3.6 - - g++-5 + - libstdc++-5-dev sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.6 - env: CLANG_VERSION=3.6 BUILD_TYPE=Release CPP=14 LIBCXX=On os: linux addons: *clang36 + # clang 3.7 C++11/14 Release libc++ - env: CLANG_VERSION=3.7 BUILD_TYPE=Release CPP=11 LIBCXX=On os: linux addons: &clang37 @@ -51,15 +57,18 @@ matrix: packages: - util-linux - clang-3.7 - - g++-5 + - libstdc++-5-dev sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.7 + - llvm-toolchain-trusty-3.7 + - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.7 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' - env: CLANG_VERSION=3.7 BUILD_TYPE=Release CPP=14 LIBCXX=On os: linux addons: *clang37 + # clang 3.8 C++11/14 Release libc++ - env: CLANG_VERSION=3.8 BUILD_TYPE=Release CPP=11 LIBCXX=On os: linux addons: &clang38 @@ -67,15 +76,15 @@ matrix: packages: - util-linux - clang-3.8 - - g++-5 + - libstdc++-5-dev sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.8 - env: CLANG_VERSION=3.8 BUILD_TYPE=Release CPP=14 LIBCXX=On os: linux addons: *clang38 + # clang 3.9 C++11/14 Release libc++ - env: CLANG_VERSION=3.9 BUILD_TYPE=Release CPP=11 LIBCXX=On os: linux addons: &clang39 @@ -83,47 +92,54 @@ matrix: packages: - util-linux - clang-3.9 - - g++-6 + - libstdc++-6-dev sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.9 - env: CLANG_VERSION=3.9 BUILD_TYPE=Release CPP=14 LIBCXX=On os: linux addons: *clang39 - - env: CLANG_VERSION=5.0 BUILD_TYPE=Debug CPP=11 ASAN=On LIBCXX=On + # clang 5 C++11/14/1z Debug/Release libc++, 11 Debug libstdc++ + - env: CLANG_VERSION=5.0 BUILD_TYPE=Debug CPP=11 LIBCXX=On os: linux addons: &clang5 apt: packages: - util-linux - clang-5.0 - - g++-6 + - libstdc++-6-dev sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise + - llvm-toolchain-trusty-5.0 + - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' + + - env: CLANG_VERSION=5.0 BUILD_TYPE=Release CPP=11 LIBCXX=On + os: linux + addons: *clang5 - - env: CLANG_VERSION=5.0 BUILD_TYPE=Release CPP=11 ASAN=On LIBCXX=On + - env: CLANG_VERSION=5.0 BUILD_TYPE=Debug CPP=14 LIBCXX=On os: linux addons: *clang5 - - env: CLANG_VERSION=5.0 BUILD_TYPE=Debug CPP=14 ASAN=On LIBCXX=On + - env: CLANG_VERSION=5.0 BUILD_TYPE=Release CPP=14 LIBCXX=On os: linux addons: *clang5 - - env: CLANG_VERSION=5.0 BUILD_TYPE=Release CPP=14 ASAN=On LIBCXX=On + - env: CLANG_VERSION=5.0 BUILD_TYPE=Debug CPP=1z LIBCXX=On os: linux addons: *clang5 - - env: CLANG_VERSION=5.0 BUILD_TYPE=Debug CPP=1z ASAN=On LIBCXX=On + - env: CLANG_VERSION=5.0 BUILD_TYPE=Release CPP=1z LIBCXX=On os: linux addons: *clang5 - - env: CLANG_VERSION=5.0 BUILD_TYPE=Release CPP=1z ASAN=On LIBCXX=On + - env: CLANG_VERSION=5.0 BUILD_TYPE=Release CPP=11 os: linux addons: *clang5 + # gcc-4.9 C++11/C++14 Release - env: GCC_VERSION=4.9 BUILD_TYPE=Release CPP=11 os: linux addons: &gcc49 @@ -137,6 +153,7 @@ matrix: os: linux addons: *gcc49 + # gcc-5 C++11/C++14 Release - env: GCC_VERSION=5 BUILD_TYPE=Release CPP=11 os: linux addons: &gcc5 @@ -150,6 +167,7 @@ matrix: os: linux addons: *gcc5 + # gcc-6 C++11/14/1z Debug/Release - env: GCC_VERSION=6 BUILD_TYPE=Debug CPP=11 os: linux addons: &gcc6 @@ -181,44 +199,51 @@ matrix: # Install dependencies before_install: - - export CHECKOUT_PATH=`pwd`; + - set -e - | if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update - brew install gnu-sed --with-default-names - brew install gnu-which --with-default-names + brew install gnu-sed + brew install gnu-which + brew upgrade cmake + export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH" fi - | if [ "${TRAVIS_OS_NAME}" == "linux" ]; then - if [ -z "$(ls -A ${TRAVIS_BUILD_DIR}/deps/cmake/bin)" ]; then - CMAKE_URL="https://cmake.org/files/v3.6/cmake-3.6.2-Linux-x86_64.tar.gz" - mkdir -p ${TRAVIS_BUILD_DIR}/deps/cmake && travis_retry wget --no-check-certificate --quiet -O - "${CMAKE_URL}" | tar --strip-components=1 -xz -C ${TRAVIS_BUILD_DIR}/deps/cmake + if [ -f ${DEPS_DIR}/cmake-${CMAKE_VERSION}/cached ]; then + echo "Using cached cmake version ${CMAKE_VERSION}." + else + CMAKE_URL="https://cmake.org/files/v3.6/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz" + mkdir -p ${DEPS_DIR}/cmake-${CMAKE_VERSION} + travis_retry wget --no-check-certificate --quiet -O - "${CMAKE_URL}" | tar --strip-components=1 -xz -C ${DEPS_DIR}/cmake-${CMAKE_VERSION} + touch ${DEPS_DIR}/cmake-${CMAKE_VERSION}/cached fi - export PATH="${TRAVIS_BUILD_DIR}/deps/cmake/bin:${PATH}" - else - if ! brew ls --version cmake &>/dev/null; then brew install cmake; fi + export PATH="${DEPS_DIR}/cmake-${CMAKE_VERSION}/bin:${PATH}" fi - if [ -n "$GCC_VERSION" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi - if [ -n "$CLANG_VERSION" ]; then export CXX="clang++-${CLANG_VERSION}" CC="clang-${CLANG_VERSION}"; fi - - which $CXX + - which $CXX && $CXX --version - which $CC - - $CXX --version - - if [ "$ASAN" == "On" ]; then export SANITIZER=Address; fi - - if [ "$LIBCXX" == "On" ]; then sudo PATH="${PATH}" CXX="$CXX" CC="$CC" ./install_libcxx.sh; fi + - if [ -n "$CLANG_VERSION" ]; then PATH="${PATH}" CXX="$CXX" CC="$CC" ./install_libcxx.sh; fi install: - - cd $CHECKOUT_PATH + - | + if [ "$LIBCXX" == "On" ]; then + CXX_FLAGS="${CXX_FLAGS} -stdlib=libc++ -nostdinc++ -cxx-isystem ${TRAVIS_BUILD_DIR}/llvm/include/c++/v1/ -Wno-unused-command-line-argument" + CXX_LINKER_FLAGS="${CXX_LINKER_FLAGS} -L ${TRAVIS_BUILD_DIR}/llvm/lib -Wl,-rpath,${TRAVIS_BUILD_DIR}/llvm/lib -lc++abi" + fi + - mkdir -p build - - cd build - - if [ -n "$CLANG_VERSION" -a "$ASAN" == "On" ]; then CXX_FLAGS="${CXX_FLAGS} -fsanitize=address,undefined,integer -fno-omit-frame-pointer -fno-sanitize=unsigned-integer-overflow"; fi - - if [ -n "$GCC_VERSION" -a "$ASAN" == "On" ]; then CXX_FLAGS="${CXX_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer"; fi - - if [ -n "$CLANG_VERSION" ]; then CXX_FLAGS="${CXX_FLAGS} -D__extern_always_inline=inline"; fi - - if [ "$LIBCXX" == "On" ]; then CXX_FLAGS="${CXX_FLAGS} -stdlib=libc++ -nostdinc++ -cxx-isystem /usr/include/c++/v1/ -Wno-unused-command-line-argument"; fi - - cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_FLAGS="${CXX_FLAGS}" -DCMAKE_EXE_LINKER_FLAGS="${CXX_LINKER_FLAGS}" -DRANGES_CXX_STD=$CPP -DRANGE_V3_NO_HEADER_CHECK=1 + # This cd works, but causes the shell to exit on OSX with set -e. I don't even. + - set +e; cd build; set -e; pwd + - cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_FLAGS="${CXX_FLAGS}" -DCMAKE_EXE_LINKER_FLAGS="${CXX_LINKER_FLAGS}" -DMETA_CXX_STD=$CPP -Wdev + - cat CMakeFiles/CMakeError.log || true + - cat CMakeFiles/CMakeOutput.log || true + - make -j2 VERBOSE=1 script: - - ctest -j2 -VV ${CTEST_FLAGS} + - ctest -j2 -VV notifications: email: false diff --git a/CMakeLists.txt b/CMakeLists.txt index 4857cc3..8879129 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,26 +1,49 @@ -cmake_minimum_required(VERSION 2.8) -set(CMAKE_LEGACY_CYGWIN_WIN32 0) +cmake_minimum_required(VERSION 3.6) +get_directory_property(is_subproject PARENT_DIRECTORY) project(Meta CXX) -if(META_CXX_STD) -else() - # Defaults to C++11 if not set: - set(META_CXX_STD 11) -endif() +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Export compilation data-base + +set(META_CXX_STD 11 CACHE STRING "C++ standard version.") + +add_library(meta INTERFACE) +target_include_directories(meta INTERFACE $) +target_include_directories(meta SYSTEM INTERFACE $/include>) -enable_testing() +include(CTest) # invokes enable_testing() and defines BUILD_TESTING variable, defaulting to ON -include_directories(include) +if("x${CMAKE_CXX_COMPILER_ID}" MATCHES "x.*Clang") + if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") + set(META_CXX_COMPILER_CLANGCL TRUE) + else() + set(META_CXX_COMPILER_CLANG TRUE) + endif() +elseif(CMAKE_COMPILER_IS_GNUCXX) + set(META_CXX_COMPILER_GCC TRUE) +elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") + set(META_CXX_COMPILER_MSVC TRUE) +endif() -if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") +if(META_CXX_COMPILER_CLANGCL OR META_CXX_COMPILER_MSVC) + # Clang-CL will blow up in the standard library if compiling with less than + # C++14, and MSVC doesn't support less than C++14 at all. + if(META_CXX_STD LESS 14) + set(META_CXX_STD 14) + endif() + # MSVC is currently supported only in 17+ mode + if(META_CXX_COMPILER_MSVC AND META_CXX_STD LESS 17) + set(META_CXX_STD 17) + endif() + set(CMAKE_CXX_FLAGS "/std:c++${META_CXX_STD} /permissive- /WX ${CMAKE_CXX_FLAGS}") +elseif(META_CXX_COMPILER_CLANG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++${META_CXX_STD} -ftemplate-backtrace-limit=0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything -Werror -pedantic-errors -Wdocumentation") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-old-style-cast") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-documentation-unknown-command -Wno-missing-prototypes") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-documentation-unknown-command -Wno-missing-prototypes") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fno-inline -g3 -fstack-protector-all") set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -g0 -march=native -mtune=native -DNDEBUG") -elseif(CMAKE_COMPILER_IS_GNUCXX) +elseif(META_CXX_COMPILER_GCC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++${META_CXX_STD} -ftemplate-backtrace-limit=0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Werror -pedantic-errors") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=deprecated-declarations") diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..83c9be4 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,51 @@ +shallow_clone: true + +image: Visual Studio 2017 + +platform: + - x64_x86 + - x64 + +configuration: + - Debug + - Release + +environment: + matrix: + - CXX: clang-cl + CPP: latest + + - CXX: cl + CPP: latest + +cache: + - C:\ninja-1.8.2 + +install: + - ps: | + if (![IO.File]::Exists("C:\ninja-1.8.2\ninja.exe")) { + Start-FileDownload 'https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-win.zip' + 7z x -y ninja-win.zip -oC:\ninja-1.8.2 + } + $env:PATH="C:\ninja-1.8.2;$env:PATH" + - for /f "tokens=1* delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath') do call "%%i\VC\Auxiliary\Build\vcvarsall.bat" %PLATFORM% + - cmake --version + - ninja --version + - clang-cl --version + - cl /Bv || exit 0 + +build_script: + - mkdir build && cd build + - ps: | + $env:CC=$env:CXX + if (($env:CXX -eq "clang-cl") -and (-not ($env:PLATFORM -eq "x64"))) { + $env:CXXFLAGS='-m32' + $env:CFLAGS='-m32' + } + - cmake .. -G Ninja -Wdev -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DMETA_CXX_STD=%CPP% + - ninja -v + +test_script: + - ctest -j2 --output-on-failure + +deploy: off diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index a73d7cc..8f740c7 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,5 +1,7 @@ add_executable(tutorial_snippets tutorial_snippets.cpp) -add_test(example.tutorial_snippets, tutorial_snippets) +target_link_libraries(tutorial_snippets meta) +add_test(example.tutorial_snippets tutorial_snippets) add_executable(tuple_cat tuple_cat.cpp) -add_test(example.tuple_cat, tuple_cat) +target_link_libraries(tuple_cat meta) +add_test(example.tuple_cat tuple_cat) diff --git a/include/meta/meta.hpp b/include/meta/meta.hpp index 60213bd..43ff423 100644 --- a/include/meta/meta.hpp +++ b/include/meta/meta.hpp @@ -2,7 +2,7 @@ // // Meta library // -// Copyright Eric Niebler 2014-2015 +// Copyright Eric Niebler 2014-present // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying @@ -21,11 +21,12 @@ #include #include -#if defined(__clang__) +#ifdef __clang__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunknown-pragmas" #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wdocumentation-deprecated-sync" +#pragma GCC diagnostic ignored "-Wmissing-variable-declarations" #endif /// \defgroup meta Meta @@ -113,3166 +114,3633 @@ /// Tiny metaprogramming library namespace meta { - /// \cond - inline namespace v1 + namespace detail { - /// \endcond - - namespace detail - { - /// Returns a \p T nullptr - template - constexpr T *_nullptr_v() - { - return nullptr; - } - } // namespace detail - - /// An empty type. - /// \ingroup datatype - struct nil_ - { - }; - - /// Type alias for \p T::type. - /// \ingroup invocation - template - using _t = typename T::type; - -#if defined(__cpp_variable_templates) || defined(META_DOXYGEN_INVOKED) - /// Variable alias for \c T::type::value - /// \note Requires C++14 or greater. - /// \ingroup invocation + /// Returns a \p T nullptr template - constexpr typename _t::value_type _v = _t::value; -#endif - - /// Lazy versions of meta actions - namespace lazy + constexpr T *_nullptr_v() { - /// \sa `meta::_t` - /// \ingroup lazy_invocation - template - using _t = defer<_t, T>; + return nullptr; } - /// An integral constant wrapper for \c std::size_t. - /// \ingroup integral - template - using size_t = std::integral_constant; - - /// An integral constant wrapper for \c bool. - /// \ingroup integral - template - using bool_ = std::integral_constant; +#if META_CXX_VARIABLE_TEMPLATES + template + META_INLINE_VAR constexpr T *nullptr_v = nullptr; +#endif + } // namespace detail - /// An integral constant wrapper for \c int. - /// \ingroup integral - template - using int_ = std::integral_constant; + /// An empty type. + /// \ingroup datatype + struct nil_ + { + }; + + /// Type alias for \p T::type. + /// \ingroup invocation + template + using _t = typename T::type; + +#if META_CXX_VARIABLE_TEMPLATES || defined(META_DOXYGEN_INVOKED) + /// Variable alias for \c T::type::value + /// \note Requires C++14 or greater. + /// \ingroup invocation + template + constexpr typename T::type::value_type _v = T::type::value; +#endif - /// An integral constant wrapper for \c char. - /// \ingroup integral - template - using char_ = std::integral_constant; - - /////////////////////////////////////////////////////////////////////////////////////////// - // Math operations - /// An integral constant wrapper around the result of incrementing the wrapped - /// integer \c - /// T::type::value. + /// Lazy versions of meta actions + namespace lazy + { + /// \sa `meta::_t` + /// \ingroup lazy_invocation + template + using _t = defer<_t, T>; + } // namespace lazy + + /// An integral constant wrapper for \c std::size_t. + /// \ingroup integral + template + using size_t = std::integral_constant; + + /// An integral constant wrapper for \c bool. + /// \ingroup integral + template + using bool_ = std::integral_constant; + + /// An integral constant wrapper for \c int. + /// \ingroup integral + template + using int_ = std::integral_constant; + + /// An integral constant wrapper for \c char. + /// \ingroup integral + template + using char_ = std::integral_constant; + + /////////////////////////////////////////////////////////////////////////////////////////// + // Math operations + /// An integral constant wrapper around the result of incrementing the wrapped integer \c + /// T::type::value. + template + using inc = std::integral_constant; + + /// An integral constant wrapper around the result of decrementing the wrapped integer \c + /// T::type::value. + template + using dec = std::integral_constant; + + /// An integral constant wrapper around the result of adding the two wrapped integers + /// \c T::type::value and \c U::type::value. + /// \ingroup math + template + using plus = std::integral_constant; + + /// An integral constant wrapper around the result of subtracting the two wrapped integers + /// \c T::type::value and \c U::type::value. + /// \ingroup math + template + using minus = std::integral_constant; + + /// An integral constant wrapper around the result of multiplying the two wrapped integers + /// \c T::type::value and \c U::type::value. + /// \ingroup math + template + using multiplies = std::integral_constant; + + /// An integral constant wrapper around the result of dividing the two wrapped integers \c + /// T::type::value and \c U::type::value. + /// \ingroup math + template + using divides = std::integral_constant; + + /// An integral constant wrapper around the result of negating the wrapped integer + /// \c T::type::value. + /// \ingroup math + template + using negate = std::integral_constant; + + /// An integral constant wrapper around the remainder of dividing the two wrapped integers + /// \c T::type::value and \c U::type::value. + /// \ingroup math + template + using modulus = std::integral_constant; + + /// A Boolean integral constant wrapper around the result of comparing \c T::type::value and + /// \c U::type::value for equality. + /// \ingroup math + template + using equal_to = bool_; + + /// A Boolean integral constant wrapper around the result of comparing \c T::type::value and + /// \c U::type::value for inequality. + /// \ingroup math + template + using not_equal_to = bool_; + + /// A Boolean integral constant wrapper around \c true if \c T::type::value is greater than + /// \c U::type::value; \c false, otherwise. + /// \ingroup math + template + using greater = bool_<(T::type::value > U::type::value)>; + + /// A Boolean integral constant wrapper around \c true if \c T::type::value is less than \c + /// U::type::value; \c false, otherwise. + /// \ingroup math + template + using less = bool_<(T::type::value < U::type::value)>; + + /// A Boolean integral constant wrapper around \c true if \c T::type::value is greater than + /// or equal to \c U::type::value; \c false, otherwise. + /// \ingroup math + template + using greater_equal = bool_<(T::type::value >= U::type::value)>; + + /// A Boolean integral constant wrapper around \c true if \c T::type::value is less than or + /// equal to \c U::type::value; \c false, otherwise. + /// \ingroup math + template + using less_equal = bool_<(T::type::value <= U::type::value)>; + + /// An integral constant wrapper around the result of bitwise-and'ing the two wrapped + /// integers \c T::type::value and \c U::type::value. + /// \ingroup math + template + using bit_and = std::integral_constant; + + /// An integral constant wrapper around the result of bitwise-or'ing the two wrapped + /// integers \c T::type::value and \c U::type::value. + /// \ingroup math + template + using bit_or = std::integral_constant; + + /// An integral constant wrapper around the result of bitwise-exclusive-or'ing the two + /// wrapped integers \c T::type::value and \c U::type::value. + /// \ingroup math + template + using bit_xor = std::integral_constant; + + /// An integral constant wrapper around the result of bitwise-complementing the wrapped + /// integer \c T::type::value. + /// \ingroup math + template + using bit_not = std::integral_constant; + + namespace lazy + { + /// \sa 'meta::int' + /// \ingroup lazy_math template - using inc = std::integral_constant; + using inc = defer; - /// An integral constant wrapper around the result of decrementing the wrapped - /// integer \c - /// T::type::value. + /// \sa 'meta::dec' + /// \ingroup lazy_math template - using dec = std::integral_constant; + using dec = defer; - /// An integral constant wrapper around the result of adding the two wrapped - /// integers - /// \c T::type::value and \c U::type::value. - /// \ingroup math + /// \sa 'meta::plus' + /// \ingroup lazy_math template - using plus = std::integral_constant; + using plus = defer; - /// An integral constant wrapper around the result of subtracting the two - /// wrapped integers - /// \c T::type::value and \c U::type::value. - /// \ingroup math + /// \sa 'meta::minus' + /// \ingroup lazy_math template - using minus = std::integral_constant; + using minus = defer; - /// An integral constant wrapper around the result of multiplying the two - /// wrapped integers - /// \c T::type::value and \c U::type::value. - /// \ingroup math + /// \sa 'meta::multiplies' + /// \ingroup lazy_math template - using multiplies = std::integral_constant; + using multiplies = defer; - /// An integral constant wrapper around the result of dividing the two wrapped - /// integers \c - /// T::type::value and \c U::type::value. - /// \ingroup math + /// \sa 'meta::divides' + /// \ingroup lazy_math template - using divides = std::integral_constant; + using divides = defer; - /// An integral constant wrapper around the result of negating the wrapped - /// integer - /// \c T::type::value. - /// \ingroup math + /// \sa 'meta::negate' + /// \ingroup lazy_math template - using negate = std::integral_constant; + using negate = defer; - /// An integral constant wrapper around the remainder of dividing the two - /// wrapped integers - /// \c T::type::value and \c U::type::value. - /// \ingroup math + /// \sa 'meta::modulus' + /// \ingroup lazy_math template - using modulus = std::integral_constant; + using modulus = defer; - /// A Boolean integral constant wrapper around the result of comparing \c - /// T::type::value and - /// \c U::type::value for equality. - /// \ingroup math + /// \sa 'meta::equal_to' + /// \ingroup lazy_math template - using equal_to = bool_; + using equal_to = defer; - /// A Boolean integral constant wrapper around the result of comparing \c - /// T::type::value and - /// \c U::type::value for inequality. - /// \ingroup math + /// \sa 'meta::not_equal_t' + /// \ingroup lazy_math template - using not_equal_to = bool_; + using not_equal_to = defer; - /// A Boolean integral constant wrapper around \c true if \c T::type::value is - /// greater than - /// \c U::type::value; \c false, otherwise. - /// \ingroup math + /// \sa 'meta::greater' + /// \ingroup lazy_math template - using greater = bool_<(T::type::value > U::type::value)>; + using greater = defer; - /// A Boolean integral constant wrapper around \c true if \c T::type::value is - /// less than \c - /// U::type::value; \c false, otherwise. - /// \ingroup math + /// \sa 'meta::less' + /// \ingroup lazy_math template - using less = bool_<(T::type::value < U::type::value)>; + using less = defer; - /// A Boolean integral constant wrapper around \c true if \c T::type::value is - /// greater than - /// or equal to \c U::type::value; \c false, otherwise. - /// \ingroup math + /// \sa 'meta::greater_equal' + /// \ingroup lazy_math template - using greater_equal = bool_<(T::type::value >= U::type::value)>; + using greater_equal = defer; - /// A Boolean integral constant wrapper around \c true if \c T::type::value is - /// less than or - /// equal to \c U::type::value; \c false, otherwise. - /// \ingroup math + /// \sa 'meta::less_equal' + /// \ingroup lazy_math template - using less_equal = bool_<(T::type::value <= U::type::value)>; + using less_equal = defer; - /// An integral constant wrapper around the result of bitwise-and'ing the two - /// wrapped - /// integers \c T::type::value and \c U::type::value. - /// \ingroup math + /// \sa 'meta::bit_and' + /// \ingroup lazy_math template - using bit_and = std::integral_constant; + using bit_and = defer; - /// An integral constant wrapper around the result of bitwise-or'ing the two - /// wrapped - /// integers \c T::type::value and \c U::type::value. - /// \ingroup math + /// \sa 'meta::bit_or' + /// \ingroup lazy_math template - using bit_or = std::integral_constant; + using bit_or = defer; - /// An integral constant wrapper around the result of bitwise-exclusive-or'ing - /// the two - /// wrapped integers \c T::type::value and \c U::type::value. - /// \ingroup math + /// \sa 'meta::bit_xor' + /// \ingroup lazy_math template - using bit_xor = std::integral_constant; + using bit_xor = defer; - /// An integral constant wrapper around the result of bitwise-complementing the - /// wrapped - /// integer \c T::type::value. - /// \ingroup math + /// \sa 'meta::bit_not' + /// \ingroup lazy_math template - using bit_not = std::integral_constant; + using bit_not = defer; + } // namespace lazy - namespace lazy + /// \cond + namespace detail + { + enum class indices_strategy_ { - /// \sa 'meta::int' - /// \ingroup lazy_math - template - using inc = defer; + done, + repeat, + recurse + }; - /// \sa 'meta::dec' - /// \ingroup lazy_math - template - using dec = defer; - - /// \sa 'meta::plus' - /// \ingroup lazy_math - template - using plus = defer; - - /// \sa 'meta::minus' - /// \ingroup lazy_math - template - using minus = defer; - - /// \sa 'meta::multiplies' - /// \ingroup lazy_math - template - using multiplies = defer; - - /// \sa 'meta::divides' - /// \ingroup lazy_math - template - using divides = defer; - - /// \sa 'meta::negate' - /// \ingroup lazy_math - template - using negate = defer; - - /// \sa 'meta::modulus' - /// \ingroup lazy_math - template - using modulus = defer; - - /// \sa 'meta::equal_to' - /// \ingroup lazy_math - template - using equal_to = defer; - - /// \sa 'meta::not_equal_t' - /// \ingroup lazy_math - template - using not_equal_to = defer; - - /// \sa 'meta::greater' - /// \ingroup lazy_math - template - using greater = defer; - - /// \sa 'meta::less' - /// \ingroup lazy_math - template - using less = defer; - - /// \sa 'meta::greater_equal' - /// \ingroup lazy_math - template - using greater_equal = defer; - - /// \sa 'meta::less_equal' - /// \ingroup lazy_math - template - using less_equal = defer; - - /// \sa 'meta::bit_and' - /// \ingroup lazy_math - template - using bit_and = defer; - - /// \sa 'meta::bit_or' - /// \ingroup lazy_math - template - using bit_or = defer; - - /// \sa 'meta::bit_xor' - /// \ingroup lazy_math - template - using bit_xor = defer; - - /// \sa 'meta::bit_not' - /// \ingroup lazy_math - template - using bit_not = defer; + constexpr indices_strategy_ strategy_(std::size_t cur, std::size_t end) + { + return cur >= end ? indices_strategy_::done + : cur * 2 <= end ? indices_strategy_::repeat + : indices_strategy_::recurse; } - /// \cond - namespace detail + template + constexpr std::size_t range_distance_(T begin, T end) { - enum class indices_strategy_ - { - done, - repeat, - recurse - }; - - constexpr indices_strategy_ strategy_(std::size_t cur, std::size_t end) - { - return cur >= end ? indices_strategy_::done - : cur * 2 <= end ? indices_strategy_::repeat - : indices_strategy_::recurse; - } - - template - constexpr std::size_t range_distance_(T begin, T end) - { - return begin <= end ? static_cast(end - begin) - : throw "The start of the integer_sequence must not be " - "greater than the end"; - } - - template - struct make_indices_ - { - using type = State; - }; - - template - struct coerce_indices_ - { - }; + return begin <= end ? static_cast(end - begin) + : throw "The start of the integer_sequence must not be " + "greater than the end"; } -/// \endcond -/////////////////////////////////////////////////////////////////////////////////////////////// -// integer_sequence -#ifndef __cpp_lib_integer_sequence - /// A container for a sequence of compile-time integer constants. - /// \ingroup integral - template - struct integer_sequence + template + struct make_indices_ { - using value_type = T; - /// \return `sizeof...(Is)` - static constexpr std::size_t size() noexcept { return sizeof...(Is); } + using type = State; }; -#endif - /////////////////////////////////////////////////////////////////////////////////////////////// - // index_sequence - /// A container for a sequence of compile-time integer constants of type - /// \c std::size_t - /// \ingroup integral - template - using index_sequence = integer_sequence; - -#if !defined(META_DOXYGEN_INVOKED) && \ - ((defined(__clang__) && __clang_major__ >= 3 && __clang_minor__ >= 8) || \ - (defined(_MSC_VER) && _MSC_FULL_VER >= 190023918)) - // Implement make_integer_sequence and make_index_sequence with the - // __make_integer_seq builtin on compilers that provide it. (Redirect - // through decltype to workaround suspected clang bug.) - /// \cond - namespace detail + template + struct coerce_indices_ { - template - __make_integer_seq make_integer_sequence_(); - } - /// \endcond + }; + } // namespace detail + /// \endcond + + /////////////////////////////////////////////////////////////////////////////////////////// + // integer_sequence +#if !META_CXX_INTEGER_SEQUENCE + /// A container for a sequence of compile-time integer constants. + /// \ingroup integral + template + struct integer_sequence + { + using value_type = T; + /// \return `sizeof...(Is)` + static constexpr std::size_t size() noexcept { return sizeof...(Is); } + }; +#endif + /////////////////////////////////////////////////////////////////////////////////////////// + // index_sequence + /// A container for a sequence of compile-time integer constants of type + /// \c std::size_t + /// \ingroup integral + template + using index_sequence = integer_sequence; + +#if META_HAS_MAKE_INTEGER_SEQ && !defined(META_DOXYGEN_INVOKED) + // Implement make_integer_sequence and make_index_sequence with the + // __make_integer_seq builtin on compilers that provide it. (Redirect + // through decltype to workaround suspected clang bug.) + /// \cond + namespace detail + { template - using make_integer_sequence = decltype(detail::make_integer_sequence_()); + __make_integer_seq make_integer_sequence_(); + } + /// \endcond - template - using make_index_sequence = make_integer_sequence; -#else - /// Generate \c index_sequence containing integer constants [0,1,2,...,N-1]. - /// \par Complexity - /// \f$ O(log(N)) \f$. - /// \ingroup integral - template - using make_index_sequence = - _t, detail::strategy_(1, N)>>; + template + using make_integer_sequence = decltype(detail::make_integer_sequence_()); - /// Generate \c integer_sequence containing integer constants [0,1,2,...,N-1]. - /// \par Complexity - /// \f$ O(log(N)) \f$. - /// \ingroup integral - template - using make_integer_sequence = - _t(N)>>>; + template + using make_index_sequence = make_integer_sequence; +#else + /// Generate \c index_sequence containing integer constants [0,1,2,...,N-1]. + /// \par Complexity + /// \f$ O(log(N)) \f$. + /// \ingroup integral + template + using make_index_sequence = + _t, detail::strategy_(1, N)>>; + + /// Generate \c integer_sequence containing integer constants [0,1,2,...,N-1]. + /// \par Complexity + /// \f$ O(log(N)) \f$. + /// \ingroup integral + template + using make_integer_sequence = + _t(N)>>>; #endif - /////////////////////////////////////////////////////////////////////////////////////////////// - // integer_range - /// Makes the integer sequence [From, To). - /// \par Complexity - /// \f$ O(log(To - From)) \f$. - /// \ingroup integral - template - using integer_range = - _t>>; + /////////////////////////////////////////////////////////////////////////////////////////// + // integer_range + /// Makes the integer sequence [From, To). + /// \par Complexity + /// \f$ O(log(To - From)) \f$. + /// \ingroup integral + template + using integer_range = + _t>>; - /// \cond - namespace detail + /// \cond + namespace detail + { + template + struct concat_indices_ { - template - struct concat_indices_ - { - }; - - template - struct concat_indices_, index_sequence> - { - using type = index_sequence; - }; - - template <> - struct make_indices_<0u, index_sequence<0>, indices_strategy_::done> - { - using type = index_sequence<>; - }; - - template - struct make_indices_, indices_strategy_::repeat> - : make_indices_, - detail::strategy_(sizeof...(Values)*2, End)> - { - }; - - template - struct make_indices_, indices_strategy_::recurse> - : concat_indices_, - make_index_sequence> - { - }; - - template - struct coerce_indices_> - { - using type = - integer_sequence(static_cast(Values) + Offset)...>; - }; - } // namespace detail - /// \endcond - - /// Evaluate the Callable \p F with the arguments \p Args. - /// \ingroup invocation - template - using invoke = typename F::template invoke; + }; - /// Lazy versions of meta actions - namespace lazy + template + struct concat_indices_, index_sequence> { - /// \sa `meta::invoke` - /// \ingroup lazy_invocation - template - using invoke = defer; - } + using type = index_sequence; + }; - /// A trait that always returns its argument \p T. Also, a Callable that always - /// returns - /// \p T. - /// \ingroup trait - /// \ingroup invocation - template - struct id + template <> + struct make_indices_<0u, index_sequence<0>, indices_strategy_::done> { - /// \cond - // Redirect through decltype for compilers that have not - // yet implemented CWG 1558: - // - static id impl(void *); - /// \endcond - - using type = T; - - template - using invoke = _t *>(nullptr)))>; + using type = index_sequence<>; }; - /// An alias for type \p T. Useful in non-deduced contexts. - /// \ingroup trait - template - using id_t = _t>; - - namespace lazy + template + struct make_indices_, indices_strategy_::repeat> + : make_indices_, + detail::strategy_(sizeof...(Values) * 2, End)> { - /// \sa `meta::id` - /// \ingroup lazy_trait - /// \ingroup lazy_invocation - template - using id = defer; - } - - /// An alias for `void`. - /// \ingroup trait - template - using void_ = invoke, Ts...>; + }; - /// \cond - namespace detail + template + struct make_indices_, indices_strategy_::recurse> + : concat_indices_, + make_index_sequence> { - template - struct is_trait_ - { - using type = std::false_type; - }; + }; - template - struct is_trait_> - { - using type = std::true_type; - }; + template + struct coerce_indices_> + { + using type = + integer_sequence(static_cast(Values) + Offset)...>; + }; + } // namespace detail + /// \endcond - template - struct is_callable_ - { - using type = std::false_type; - }; + /// Evaluate the Invocable \p Fn with the arguments \p Args. + /// \ingroup invocation + template + using invoke = typename Fn::template invoke; - template - struct is_callable_>> - { - using type = std::true_type; - }; + /// Lazy versions of meta actions + namespace lazy + { + /// \sa `meta::invoke` + /// \ingroup lazy_invocation + template + using invoke = defer; + } // namespace lazy + + /// A Trait that always returns its argument \p T. It is also an Invocable + /// that always returns \p T. + /// \ingroup trait + /// \ingroup invocation + template + struct id + { +#if defined(META_WORKAROUND_CWG_1558) && !defined(META_DOXYGEN_INVOKED) + // Redirect through decltype for compilers that have not + // yet implemented CWG 1558: + static id impl(void *); - struct defer_if_ - { - template