diff --git a/.gitignore b/.gitignore index ee5ca3c..cbb4a5c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ CMakeFiles +build +include/catch tests/CMakeFiles tests/Debug *.opensdf diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index b198402..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "tests/unittest-cpp"] - path = tests/unittest-cpp - url = https://github.com/unittest-cpp/unittest-cpp.git diff --git a/.travis.yml b/.travis.yml index 53d110d..82b8ec2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ cache: - ${TRAVIS_BUILD_DIR}/deps/llvm-3.6.2/install - ${TRAVIS_BUILD_DIR}/deps/llvm-3.7.1/install - ${TRAVIS_BUILD_DIR}/deps/llvm-3.8.1/install - - ${TRAVIS_BUILD_DIR}/deps/llvm-3.9.0/install + - ${TRAVIS_BUILD_DIR}/deps/llvm-3.9.1/install matrix: include: @@ -61,6 +61,19 @@ matrix: - env: CLANG_VERSION=3.8 BUILD_TYPE=Release os: linux addons: *clang38 + - env: CLANG_VERSION=3.9 BUILD_TYPE=Debug + os: linux + addons: &clang39 + apt: + packages: + - clang-3.9 + - g++-5 + sources: &sources + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.9 + - env: CLANG_VERSION=3.9 BUILD_TYPE=Release + os: linux + addons: *clang39 - env: GCC_VERSION=5 BUILD_TYPE=Debug os: linux addons: &gcc5 @@ -110,7 +123,7 @@ install: if [[ "$CLANG_VERSION" == "3.6" ]]; then LLVM_VERSION="3.6.2"; fi if [[ "$CLANG_VERSION" == "3.7" ]]; then LLVM_VERSION="3.7.1"; fi if [[ "$CLANG_VERSION" == "3.8" ]]; then LLVM_VERSION="3.8.1"; fi - if [[ "$CLANG_VERSION" == "3.9" ]]; then LLVM_VERSION="3.9.0"; fi + if [[ "$CLANG_VERSION" == "3.9" ]]; then LLVM_VERSION="3.9.1"; fi LLVM_ROOT="${DEPS_DIR}/llvm-${LLVM_VERSION}" LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz" LIBCXX_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxx-${LLVM_VERSION}.src.tar.xz" diff --git a/CMakeLists.txt b/CMakeLists.txt index e4e4e48..2143537 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,12 +2,15 @@ cmake_minimum_required(VERSION 2.8.7) project(GSL CXX) +include(ExternalProject) +find_package(Git REQUIRED) + # creates a library GSL which is an interface (header files only) add_library(GSL INTERFACE) # when minimum version required is 3.8.0 remove if below # both branches do exactly the same thing -if ( CMAKE_MAJOR_VERSION VERSION_LESS 3.7.9) +if (CMAKE_MAJOR_VERSION VERSION_LESS 3.7.9) if (NOT MSVC) include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14) @@ -16,7 +19,7 @@ if ( CMAKE_MAJOR_VERSION VERSION_LESS 3.7.9) else() message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++14 support. Please use a different C++ compiler.") endif() - + endif() else () # set the GSL library to be compiled only with c++14 @@ -41,7 +44,7 @@ target_include_directories(GSL INTERFACE ) # add natvis file to the library so it will automatically be loaded into Visual Studio -target_sources(GSL INTERFACE +target_sources(GSL INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/GSL.natvis ) diff --git a/README.md b/README.md index 120e2b1..03ac9e7 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,6 @@ contributing any changes that were necessary back to this project to benefit the To build the tests, you will require the following: * [CMake](http://cmake.org), version 2.8.7 or later to be installed and in your PATH. -* [UnitTest-cpp](https://github.com/Microsoft/unittest-cpp), to be cloned under the [tests/unittest-cpp](./tests/unittest-cpp) directory -of your GSL source. These steps assume the source code of this repository has been cloned into a directory named `c:\GSL`. @@ -55,11 +53,11 @@ These steps assume the source code of this repository has been cloned into a dir cmake -G "Visual Studio 14 2015" c:\GSL -3. Build the test suite (in this case, in the Debug configuration, Release is another good choice). +3. Build the test suite (in this case, in the Debug configuration, Release is another good choice). cmake --build . --config Debug -4. Run the test suite. +4. Run the test suite. ctest -C Debug diff --git a/appveyor.yml b/appveyor.yml index 5acfd11..d978a5d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,16 +13,15 @@ image: - Visual Studio 2017 cache: - - C:\cmake-3.7.2-win32-x86 + - C:\cmake-3.8.0-win32-x86 install: - - git clone --quiet --depth=1 https://github.com/Microsoft/unittest-cpp.git tests/unittest-cpp - ps: | - if (![IO.File]::Exists("C:\cmake-3.7.2-win32-x86\bin\cmake.exe")) { - Start-FileDownload 'https://cmake.org/files/v3.7/cmake-3.7.2-win32-x86.zip' - 7z x -y cmake-3.7.2-win32-x86.zip -oC:\ + if (![IO.File]::Exists("C:\cmake-3.8.0-win32-x86\bin\cmake.exe")) { + Start-FileDownload 'https://cmake.org/files/v3.8/cmake-3.8.0-win32-x86.zip' + 7z x -y cmake-3.8.0-win32-x86.zip -oC:\ } - $env:PATH="C:\cmake-3.7.2-win32-x86\bin;$env:PATH" + $env:PATH="C:\cmake-3.8.0-win32-x86\bin;$env:PATH" before_build: - ps: | diff --git a/include/gsl/multi_span b/include/gsl/multi_span index 319aded..fcea983 100644 --- a/include/gsl/multi_span +++ b/include/gsl/multi_span @@ -41,6 +41,7 @@ // turn off some warnings that are noisy about our Expects statements #pragma warning(push) #pragma warning(disable : 4127) // conditional expression is constant +#pragma warning(disable : 4702) // unreachable code #if _MSC_VER < 1910 #pragma push_macro("constexpr") diff --git a/include/gsl/span b/include/gsl/span index b344314..d531a87 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -37,6 +37,7 @@ // turn off some warnings that are noisy about our Expects statements #pragma warning(disable : 4127) // conditional expression is constant +#pragma warning(disable : 4702) // unreachable code // blanket turn off warnings from CppCoreCheck for now // so people aren't annoyed by them when running the tool. diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index eb08360..f963c23 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,15 +5,21 @@ project(GSLTests CXX) # will make visual studio generated project group files set_property(GLOBAL PROPERTY USE_FOLDERS ON) -if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/unittest-cpp/CMakeLists.txt) - find_package(Git) - execute_process( - COMMAND ${GIT_EXECUTABLE} submodule update --init - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - ) -endif() +list(APPEND CATCH_CMAKE_ARGS + "-DCMAKE_INSTALL_PREFIX=${CMAKE_SOURCE_DIR}" + "-DNO_SELFTEST=true" +) -add_subdirectory(unittest-cpp) +# add catch +ExternalProject_Add( + catch + PREFIX ${CMAKE_BINARY_DIR}/catch + GIT_REPOSITORY https://github.com/philsquared/Catch.git +# GIT_TAG v1.9.4 uncomment once v1.9.4 is available + CMAKE_ARGS ${CATCH_CMAKE_ARGS} + LOG_DOWNLOAD 1 + UPDATE_DISCONNECTED 1 +) # this interface adds compile options to how the tests are run # please try to keep entries ordered =) @@ -42,24 +48,29 @@ target_compile_options(gsl_tests_config INTERFACE > ) -# set test to include the unittest-cpp headers -# this shiuld be removed when UnitTest++ has the proper headers -target_include_directories(gsl_tests_config INTERFACE - ./unittest-cpp -) - # set definitions for tests target_compile_definitions(gsl_tests_config INTERFACE GSL_THROW_ON_CONTRACT_VIOLATION ) +# create the main executable for each test. this reduces the compile time +# of each test by pre-compiling catch. +add_library(test_catch STATIC test.cpp) +target_link_libraries(test_catch + GSL + gsl_tests_config +) +add_dependencies(test_catch catch) +set_property(TARGET test_catch PROPERTY FOLDER "GSL_tests") + function(add_gsl_test name) add_executable(${name} ${name}.cpp) target_link_libraries(${name} - UnitTest++ GSL + test_catch gsl_tests_config ) + add_dependencies(${name} catch) add_test( ${name} ${name} diff --git a/tests/algorithm_tests.cpp b/tests/algorithm_tests.cpp index 7b5f429..045fd3e 100644 --- a/tests/algorithm_tests.cpp +++ b/tests/algorithm_tests.cpp @@ -14,7 +14,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include @@ -23,188 +23,182 @@ using namespace std; using namespace gsl; -SUITE(copy_tests) +TEST_CASE("same_type") { - - TEST(same_type) + // dynamic source and destination span { - // dynamic source and destination span - { - std::array src{1, 2, 3, 4, 5}; - std::array dst{}; + std::array src{1, 2, 3, 4, 5}; + std::array dst{}; - span src_span(src); - span dst_span(dst); + span src_span(src); + span dst_span(dst); - copy(src_span, dst_span); - copy(src_span, dst_span.subspan(src_span.size())); + copy(src_span, dst_span); + copy(src_span, dst_span.subspan(src_span.size())); - for (std::size_t i = 0; i < src.size(); ++i) { - CHECK(dst[i] == src[i]); - CHECK(dst[i + src.size()] == src[i]); - } - } - - // static source and dynamic destination span - { - std::array src{1, 2, 3, 4, 5}; - std::array dst{}; - - span src_span(src); - span dst_span(dst); - - copy(src_span, dst_span); - copy(src_span, dst_span.subspan(src_span.size())); - - for (std::size_t i = 0; i < src.size(); ++i) { - CHECK(dst[i] == src[i]); - CHECK(dst[i + src.size()] == src[i]); - } - } - - // dynamic source and static destination span - { - std::array src{1, 2, 3, 4, 5}; - std::array dst{}; - - span src_span(src); - span dst_span(dst); - - copy(src_span, dst_span); - copy(src_span, dst_span.subspan(src_span.size())); - - for (std::size_t i = 0; i < src.size(); ++i) { - CHECK(dst[i] == src[i]); - CHECK(dst[i + src.size()] == src[i]); - } - } - - // static source and destination span - { - std::array src{1, 2, 3, 4, 5}; - std::array dst{}; - - span src_span(src); - span dst_span(dst); - - copy(src_span, dst_span); - copy(src_span, dst_span.subspan(src_span.size())); - - for (std::size_t i = 0; i < src.size(); ++i) { - CHECK(dst[i] == src[i]); - CHECK(dst[i + src.size()] == src[i]); - } + for (std::size_t i = 0; i < src.size(); ++i) { + CHECK(dst[i] == src[i]); + CHECK(dst[i + src.size()] == src[i]); } } - TEST(compatible_type) + // static source and dynamic destination span { - // dynamic source and destination span - { - std::array src{1, 2, 3, 4, 5}; - std::array dst{}; + std::array src{1, 2, 3, 4, 5}; + std::array dst{}; - span src_span(src); - span dst_span(dst); + span src_span(src); + span dst_span(dst); - copy(src_span, dst_span); - copy(src_span, dst_span.subspan(src_span.size())); + copy(src_span, dst_span); + copy(src_span, dst_span.subspan(src_span.size())); - for (std::size_t i = 0; i < src.size(); ++i) { - CHECK(dst[i] == src[i]); - CHECK(dst[i + src.size()] == src[i]); - } - } - - // static source and dynamic destination span - { - std::array src{1, 2, 3, 4, 5}; - std::array dst{}; - - span src_span(src); - span dst_span(dst); - - copy(src_span, dst_span); - copy(src_span, dst_span.subspan(src_span.size())); - - for (std::size_t i = 0; i < src.size(); ++i) { - CHECK(dst[i] == src[i]); - CHECK(dst[i + src.size()] == src[i]); - } - } - - // dynamic source and static destination span - { - std::array src{1, 2, 3, 4, 5}; - std::array dst{}; - - span src_span(src); - span dst_span(dst); - - copy(src_span, dst_span); - copy(src_span, dst_span.subspan(src_span.size())); - - for (std::size_t i = 0; i < src.size(); ++i) { - CHECK(dst[i] == src[i]); - CHECK(dst[i + src.size()] == src[i]); - } - } - - // static source and destination span - { - std::array src{1, 2, 3, 4, 5}; - std::array dst{}; - - span src_span(src); - span dst_span(dst); - - copy(src_span, dst_span); - copy(src_span, dst_span.subspan(src_span.size())); - - for (std::size_t i = 0; i < src.size(); ++i) { - CHECK(dst[i] == src[i]); - CHECK(dst[i + src.size()] == src[i]); - } + for (std::size_t i = 0; i < src.size(); ++i) { + CHECK(dst[i] == src[i]); + CHECK(dst[i + src.size()] == src[i]); } } -#ifdef CONFIRM_COMPILATION_ERRORS - TEST(incompatible_type) + // dynamic source and static destination span { - std::array src{1, 2, 3, 4}; - std::array dst{}; + std::array src{1, 2, 3, 4, 5}; + std::array dst{}; - span src_span_dyn(src); - span src_span_static(src); - span dst_span_dyn(dst); - span dst_span_static(dst); + span src_span(src); + span dst_span(dst); - // every line should produce a compilation error - copy(src_span_dyn, dst_span_dyn); - copy(src_span_dyn, dst_span_static); - copy(src_span_static, dst_span_dyn); - copy(src_span_static, dst_span_static); + copy(src_span, dst_span); + copy(src_span, dst_span.subspan(src_span.size())); + + for (std::size_t i = 0; i < src.size(); ++i) { + CHECK(dst[i] == src[i]); + CHECK(dst[i + src.size()] == src[i]); + } } -#endif - TEST(small_destination_span) + // static source and destination span { - std::array src{1, 2, 3, 4}; - std::array dst{}; + std::array src{1, 2, 3, 4, 5}; + std::array dst{}; - span src_span_dyn(src); - span src_span_static(src); - span dst_span_dyn(dst); - span dst_span_static(dst); + span src_span(src); + span dst_span(dst); - CHECK_THROW(copy(src_span_dyn, dst_span_dyn), fail_fast); - CHECK_THROW(copy(src_span_dyn, dst_span_static), fail_fast); - CHECK_THROW(copy(src_span_static, dst_span_dyn), fail_fast); + copy(src_span, dst_span); + copy(src_span, dst_span.subspan(src_span.size())); -#ifdef CONFIRM_COMPILATION_ERRORS - copy(src_span_static, dst_span_static); -#endif + for (std::size_t i = 0; i < src.size(); ++i) { + CHECK(dst[i] == src[i]); + CHECK(dst[i + src.size()] == src[i]); + } } } -int main() { return UnitTest::RunAllTests(); } +TEST_CASE("compatible_type") +{ + // dynamic source and destination span + { + std::array src{1, 2, 3, 4, 5}; + std::array dst{}; + + span src_span(src); + span dst_span(dst); + + copy(src_span, dst_span); + copy(src_span, dst_span.subspan(src_span.size())); + + for (std::size_t i = 0; i < src.size(); ++i) { + CHECK(dst[i] == src[i]); + CHECK(dst[i + src.size()] == src[i]); + } + } + + // static source and dynamic destination span + { + std::array src{1, 2, 3, 4, 5}; + std::array dst{}; + + span src_span(src); + span dst_span(dst); + + copy(src_span, dst_span); + copy(src_span, dst_span.subspan(src_span.size())); + + for (std::size_t i = 0; i < src.size(); ++i) { + CHECK(dst[i] == src[i]); + CHECK(dst[i + src.size()] == src[i]); + } + } + + // dynamic source and static destination span + { + std::array src{1, 2, 3, 4, 5}; + std::array dst{}; + + span src_span(src); + span dst_span(dst); + + copy(src_span, dst_span); + copy(src_span, dst_span.subspan(src_span.size())); + + for (std::size_t i = 0; i < src.size(); ++i) { + CHECK(dst[i] == src[i]); + CHECK(dst[i + src.size()] == src[i]); + } + } + + // static source and destination span + { + std::array src{1, 2, 3, 4, 5}; + std::array dst{}; + + span src_span(src); + span dst_span(dst); + + copy(src_span, dst_span); + copy(src_span, dst_span.subspan(src_span.size())); + + for (std::size_t i = 0; i < src.size(); ++i) { + CHECK(dst[i] == src[i]); + CHECK(dst[i + src.size()] == src[i]); + } + } +} + +#ifdef CONFIRM_COMPILATION_ERRORS +TEST_CASE("incompatible_type") +{ + std::array src{1, 2, 3, 4}; + std::array dst{}; + + span src_span_dyn(src); + span src_span_static(src); + span dst_span_dyn(dst); + span dst_span_static(dst); + + // every line should produce a compilation error + copy(src_span_dyn, dst_span_dyn); + copy(src_span_dyn, dst_span_static); + copy(src_span_static, dst_span_dyn); + copy(src_span_static, dst_span_static); +} +#endif + +TEST_CASE("small_destination_span") +{ + std::array src{1, 2, 3, 4}; + std::array dst{}; + + span src_span_dyn(src); + span src_span_static(src); + span dst_span_dyn(dst); + span dst_span_static(dst); + + CHECK_THROWS_AS(copy(src_span_dyn, dst_span_dyn), fail_fast); + CHECK_THROWS_AS(copy(src_span_dyn, dst_span_static), fail_fast); + CHECK_THROWS_AS(copy(src_span_static, dst_span_dyn), fail_fast); + +#ifdef CONFIRM_COMPILATION_ERRORS + copy(src_span_static, dst_span_static); +#endif +} diff --git a/tests/assertion_tests.cpp b/tests/assertion_tests.cpp index b817a6d..42966d1 100644 --- a/tests/assertion_tests.cpp +++ b/tests/assertion_tests.cpp @@ -14,38 +14,33 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include using namespace gsl; -SUITE(assertion_tests) +int f(int i) { - int f(int i) - { - Expects(i > 0 && i < 10); - return i; - } - - TEST(expects) - { - CHECK(f(2) == 2); - CHECK_THROW(f(10), fail_fast); - } - - int g(int i) - { - i++; - Ensures(i > 0 && i < 10); - return i; - } - - TEST(ensures) - { - CHECK(g(2) == 3); - CHECK_THROW(g(9), fail_fast); - } + Expects(i > 0 && i < 10); + return i; } -int main(int, const char* []) { return UnitTest::RunAllTests(); } +TEST_CASE("expects") +{ + CHECK(f(2) == 2); + CHECK_THROWS_AS(f(10), fail_fast); +} + +int g(int i) +{ + i++; + Ensures(i > 0 && i < 10); + return i; +} + +TEST_CASE("ensures") +{ + CHECK(g(2) == 3); + CHECK_THROWS_AS(g(9), fail_fast); +} diff --git a/tests/at_tests.cpp b/tests/at_tests.cpp index 96e00f3..78e8e3d 100644 --- a/tests/at_tests.cpp +++ b/tests/at_tests.cpp @@ -14,7 +14,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include @@ -23,70 +23,67 @@ using gsl::fail_fast; -SUITE(at_tests) +TEST_CASE("static_array") { - TEST(static_array) - { - int a[4] = {1, 2, 3, 4}; - const int(&c_a)[4] = a; + int a[4] = {1, 2, 3, 4}; + const int(&c_a)[4] = a; - for (int i = 0; i < 4; ++i) { - CHECK(&gsl::at(a, i) == &a[i]); - CHECK(&gsl::at(c_a, i) == &a[i]); - } - - CHECK_THROW(gsl::at(a, -1), fail_fast); - CHECK_THROW(gsl::at(a, 4), fail_fast); - CHECK_THROW(gsl::at(c_a, -1), fail_fast); - CHECK_THROW(gsl::at(c_a, 4), fail_fast); + for (int i = 0; i < 4; ++i) { + CHECK(&gsl::at(a, i) == &a[i]); + CHECK(&gsl::at(c_a, i) == &a[i]); } - TEST(std_array) - { - std::array a = {1, 2, 3, 4}; - const std::array& c_a = a; + CHECK_THROWS_AS(gsl::at(a, -1), fail_fast); + CHECK_THROWS_AS(gsl::at(a, 4), fail_fast); + CHECK_THROWS_AS(gsl::at(c_a, -1), fail_fast); + CHECK_THROWS_AS(gsl::at(c_a, 4), fail_fast); +} - for (int i = 0; i < 4; ++i) { - CHECK(&gsl::at(a, i) == &a[static_cast(i)]); - CHECK(&gsl::at(c_a, i) == &a[static_cast(i)]); - } +TEST_CASE("std_array") +{ + std::array a = {1, 2, 3, 4}; + const std::array& c_a = a; - CHECK_THROW(gsl::at(a, -1), fail_fast); - CHECK_THROW(gsl::at(a, 4), fail_fast); - CHECK_THROW(gsl::at(c_a, -1), fail_fast); - CHECK_THROW(gsl::at(c_a, 4), fail_fast); + for (int i = 0; i < 4; ++i) { + CHECK(&gsl::at(a, i) == &a[static_cast(i)]); + CHECK(&gsl::at(c_a, i) == &a[static_cast(i)]); } - TEST(StdVector) - { - std::vector a = {1, 2, 3, 4}; - const std::vector& c_a = a; + CHECK_THROWS_AS(gsl::at(a, -1), fail_fast); + CHECK_THROWS_AS(gsl::at(a, 4), fail_fast); + CHECK_THROWS_AS(gsl::at(c_a, -1), fail_fast); + CHECK_THROWS_AS(gsl::at(c_a, 4), fail_fast); +} - for (int i = 0; i < 4; ++i) { - CHECK(&gsl::at(a, i) == &a[static_cast(i)]); - CHECK(&gsl::at(c_a, i) == &a[static_cast(i)]); - } +TEST_CASE("StdVector") +{ + std::vector a = {1, 2, 3, 4}; + const std::vector& c_a = a; - CHECK_THROW(gsl::at(a, -1), fail_fast); - CHECK_THROW(gsl::at(a, 4), fail_fast); - CHECK_THROW(gsl::at(c_a, -1), fail_fast); - CHECK_THROW(gsl::at(c_a, 4), fail_fast); + for (int i = 0; i < 4; ++i) { + CHECK(&gsl::at(a, i) == &a[static_cast(i)]); + CHECK(&gsl::at(c_a, i) == &a[static_cast(i)]); } - TEST(InitializerList) - { - std::initializer_list a = {1, 2, 3, 4}; + CHECK_THROWS_AS(gsl::at(a, -1), fail_fast); + CHECK_THROWS_AS(gsl::at(a, 4), fail_fast); + CHECK_THROWS_AS(gsl::at(c_a, -1), fail_fast); + CHECK_THROWS_AS(gsl::at(c_a, 4), fail_fast); +} - for (int i = 0; i < 4; ++i) { - CHECK(gsl::at(a, i) == i + 1); - CHECK(gsl::at({1, 2, 3, 4}, i) == i + 1); - } +TEST_CASE("InitializerList") +{ + std::initializer_list a = {1, 2, 3, 4}; - CHECK_THROW(gsl::at(a, -1), fail_fast); - CHECK_THROW(gsl::at(a, 4), fail_fast); - CHECK_THROW(gsl::at({1, 2, 3, 4}, -1), fail_fast); - CHECK_THROW(gsl::at({1, 2, 3, 4}, 4), fail_fast); + for (int i = 0; i < 4; ++i) { + CHECK(gsl::at(a, i) == i + 1); + CHECK(gsl::at({1, 2, 3, 4}, i) == i + 1); } + + CHECK_THROWS_AS(gsl::at(a, -1), fail_fast); + CHECK_THROWS_AS(gsl::at(a, 4), fail_fast); + CHECK_THROWS_AS(gsl::at({1, 2, 3, 4}, -1), fail_fast); + CHECK_THROWS_AS(gsl::at({1, 2, 3, 4}, 4), fail_fast); } #if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910 @@ -111,5 +108,3 @@ static constexpr bool test_constexpr() static_assert(test_constexpr(), "FAIL"); #endif - -int main() { return UnitTest::RunAllTests(); } diff --git a/tests/bounds_tests.cpp b/tests/bounds_tests.cpp index b010c3b..51b5393 100644 --- a/tests/bounds_tests.cpp +++ b/tests/bounds_tests.cpp @@ -14,7 +14,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include @@ -28,73 +28,68 @@ namespace void use(std::ptrdiff_t&) {} } -SUITE(bounds_test) +TEST_CASE("basic_bounds") { - TEST(basic_bounds) - { - for (auto point : static_bounds{2}) { - for (decltype(point)::size_type j = 0; - j < static_cast(decltype(point)::rank); j++) - { - use(j); - use(point[static_cast(j)]); - } + for (auto point : static_bounds{2}) { + for (decltype(point)::size_type j = 0; + j < static_cast(decltype(point)::rank); j++) + { + use(j); + use(point[static_cast(j)]); } } - - TEST(bounds_basic) - { - static_bounds<3, 4, 5> b; - const auto a = b.slice(); - (void) a; - static_bounds<4, dynamic_range, 2> x{4}; - x.slice().slice(); - } - - TEST(arrayview_iterator) - { - static_bounds<4, dynamic_range, 2> bounds{3}; - - const auto itr = bounds.begin(); - (void) itr; -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span av(nullptr, bounds); - - auto itr2 = av.cbegin(); - - for (auto& v : av) { - v = 4; - } - fill(av.begin(), av.end(), 0); -#endif - } - - TEST(bounds_convertible) - { - static_bounds<7, 4, 2> b1; - static_bounds<7, dynamic_range, 2> b2 = b1; - (void) b2; -#ifdef CONFIRM_COMPILATION_ERRORS - static_bounds<7, dynamic_range, 1> b4 = b2; -#endif - - static_bounds b3 = b1; - static_bounds<7, 4, 2> b4 = b3; - (void) b4; - - static_bounds b11; - - static_bounds b5; - static_bounds<34> b6; - - b5 = static_bounds<20>(); - CHECK_THROW(b6 = b5, fail_fast); - b5 = static_bounds<34>(); - b6 = b5; - - CHECK(b5 == b6); - CHECK(b5.size() == b6.size()); - } } -int main(int, const char* []) { return UnitTest::RunAllTests(); } +TEST_CASE("bounds_basic") +{ + static_bounds<3, 4, 5> b; + const auto a = b.slice(); + (void) a; + static_bounds<4, dynamic_range, 2> x{4}; + x.slice().slice(); +} + +TEST_CASE("arrayview_iterator") +{ + static_bounds<4, dynamic_range, 2> bounds{3}; + + const auto itr = bounds.begin(); + (void) itr; +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span av(nullptr, bounds); + + auto itr2 = av.cbegin(); + + for (auto& v : av) { + v = 4; + } + fill(av.begin(), av.end(), 0); +#endif +} + +TEST_CASE("bounds_convertible") +{ + static_bounds<7, 4, 2> b1; + static_bounds<7, dynamic_range, 2> b2 = b1; + (void) b2; +#ifdef CONFIRM_COMPILATION_ERRORS + static_bounds<7, dynamic_range, 1> b4 = b2; +#endif + + static_bounds b3 = b1; + static_bounds<7, 4, 2> b4 = b3; + (void) b4; + + static_bounds b11; + + static_bounds b5; + static_bounds<34> b6; + + b5 = static_bounds<20>(); + CHECK_THROWS_AS(b6 = b5, fail_fast); + b5 = static_bounds<34>(); + b6 = b5; + + CHECK(b5 == b6); + CHECK(b5.size() == b6.size()); +} diff --git a/tests/byte_tests.cpp b/tests/byte_tests.cpp index 753936e..2c6259d 100644 --- a/tests/byte_tests.cpp +++ b/tests/byte_tests.cpp @@ -14,7 +14,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include @@ -31,105 +31,101 @@ using namespace gsl; namespace { -SUITE(byte_tests) +TEST_CASE("construction") { - TEST(construction) { - { - const byte b = static_cast(4); - CHECK(static_cast(b) == 4); - } - - { - const byte b = byte(12); - CHECK(static_cast(b) == 12); - } - - { - const byte b = to_byte<12>(); - CHECK(static_cast(b) == 12); - } - { - const unsigned char uc = 12; - const byte b = to_byte(uc); - CHECK(static_cast(b) == 12); - } - - // waiting for C++17 enum class direct initializer support - //{ - // byte b { 14 }; - // CHECK(static_cast(b) == 14); - //} + const byte b = static_cast(4); + CHECK(static_cast(b) == 4); } - TEST(bitwise_operations) { - const byte b = to_byte<0xFF>(); - - byte a = to_byte<0x00>(); - CHECK((b | a) == to_byte<0xFF>()); - CHECK(a == to_byte<0x00>()); - - a |= b; - CHECK(a == to_byte<0xFF>()); - - a = to_byte<0x01>(); - CHECK((b & a) == to_byte<0x01>()); - - a &= b; - CHECK(a == to_byte<0x01>()); - - CHECK((b ^ a) == to_byte<0xFE>()); - - CHECK(a == to_byte<0x01>()); - a ^= b; - CHECK(a == to_byte<0xFE>()); - - a = to_byte<0x01>(); - CHECK(~a == to_byte<0xFE>()); - - a = to_byte<0xFF>(); - CHECK((a << 4) == to_byte<0xF0>()); - CHECK((a >> 4) == to_byte<0x0F>()); - - a <<= 4; - CHECK(a == to_byte<0xF0>()); - a >>= 4; - CHECK(a == to_byte<0x0F>()); + const byte b = byte(12); + CHECK(static_cast(b) == 12); } - TEST(to_integer) { - const byte b = to_byte<0x12>(); - - CHECK(0x12 == gsl::to_integer(b)); - CHECK(0x12 == gsl::to_integer(b)); - CHECK(0x12 == gsl::to_integer(b)); - CHECK(0x12 == gsl::to_integer(b)); - - CHECK(0x12 == gsl::to_integer(b)); - CHECK(0x12 == gsl::to_integer(b)); - CHECK(0x12 == gsl::to_integer(b)); - CHECK(0x12 == gsl::to_integer(b)); - - // CHECK(0x12 == gsl::to_integer(b)); // expect compile-time error - // CHECK(0x12 == gsl::to_integer(b)); // expect compile-time error + const byte b = to_byte<12>(); + CHECK(static_cast(b) == 12); + } + { + const unsigned char uc = 12; + const byte b = to_byte(uc); + CHECK(static_cast(b) == 12); } - int modify_both(gsl::byte & b, int& i) - { - i = 10; - b = to_byte<5>(); - return i; - } - - TEST(aliasing) - { - int i{0}; - const int res = modify_both(reinterpret_cast(i), i); - CHECK(res == i); - } -} + // waiting for C++17 enum class direct initializer support + //{ + // byte b { 14 }; + // CHECK(static_cast(b) == 14); + //} } -int main(int, const char* []) { return UnitTest::RunAllTests(); } +TEST_CASE("bitwise_operations") +{ + const byte b = to_byte<0xFF>(); + + byte a = to_byte<0x00>(); + CHECK((b | a) == to_byte<0xFF>()); + CHECK(a == to_byte<0x00>()); + + a |= b; + CHECK(a == to_byte<0xFF>()); + + a = to_byte<0x01>(); + CHECK((b & a) == to_byte<0x01>()); + + a &= b; + CHECK(a == to_byte<0x01>()); + + CHECK((b ^ a) == to_byte<0xFE>()); + + CHECK(a == to_byte<0x01>()); + a ^= b; + CHECK(a == to_byte<0xFE>()); + + a = to_byte<0x01>(); + CHECK(~a == to_byte<0xFE>()); + + a = to_byte<0xFF>(); + CHECK((a << 4) == to_byte<0xF0>()); + CHECK((a >> 4) == to_byte<0x0F>()); + + a <<= 4; + CHECK(a == to_byte<0xF0>()); + a >>= 4; + CHECK(a == to_byte<0x0F>()); +} + +TEST_CASE("to_integer") +{ + const byte b = to_byte<0x12>(); + + CHECK(0x12 == gsl::to_integer(b)); + CHECK(0x12 == gsl::to_integer(b)); + CHECK(0x12 == gsl::to_integer(b)); + CHECK(0x12 == gsl::to_integer(b)); + + CHECK(0x12 == gsl::to_integer(b)); + CHECK(0x12 == gsl::to_integer(b)); + CHECK(0x12 == gsl::to_integer(b)); + CHECK(0x12 == gsl::to_integer(b)); + + // CHECK(0x12 == gsl::to_integer(b)); // expect compile-time error + // CHECK(0x12 == gsl::to_integer(b)); // expect compile-time error +} + +int modify_both(gsl::byte & b, int& i) +{ + i = 10; + b = to_byte<5>(); + return i; +} + +TEST_CASE("aliasing") +{ + int i{0}; + const int res = modify_both(reinterpret_cast(i), i); + CHECK(res == i); +} + +} diff --git a/tests/multi_span_tests.cpp b/tests/multi_span_tests.cpp index 5f829e1..af58d76 100644 --- a/tests/multi_span_tests.cpp +++ b/tests/multi_span_tests.cpp @@ -14,7 +14,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include @@ -38,1324 +38,1324 @@ struct DerivedClass : BaseClass }; } -SUITE(multi_span_tests) +TEST_CASE("default_constructor") { - - TEST(default_constructor) { - { - multi_span s; - CHECK(s.length() == 0 && s.data() == nullptr); + multi_span s; + CHECK((s.length() == 0 && s.data() == nullptr)); - multi_span cs; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - - { - multi_span s; - CHECK(s.length() == 0 && s.data() == nullptr); - - multi_span cs; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s; - CHECK(s.length() == 1 && s.data() == nullptr); // explains why it can't compile -#endif - } - - { - multi_span s{}; - CHECK(s.length() == 0 && s.data() == nullptr); - - multi_span cs{}; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } + multi_span cs; + CHECK((cs.length() == 0 && cs.data() == nullptr)); } - TEST(from_nullptr_constructor) { - { - multi_span s = nullptr; - CHECK(s.length() == 0 && s.data() == nullptr); + multi_span s; + CHECK((s.length() == 0 && s.data() == nullptr)); - multi_span cs = nullptr; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - - { - multi_span s = nullptr; - CHECK(s.length() == 0 && s.data() == nullptr); - - multi_span cs = nullptr; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s = nullptr; - CHECK(s.length() == 1 && s.data() == nullptr); // explains why it can't compile -#endif - } - - { - multi_span s{nullptr}; - CHECK(s.length() == 0 && s.data() == nullptr); - - multi_span cs{nullptr}; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - - { - multi_span s{nullptr}; - CHECK(s.length() == 0 && s.data() == nullptr); - - multi_span cs{nullptr}; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } + multi_span cs; + CHECK((cs.length() == 0 && cs.data() == nullptr)); } - TEST(from_nullptr_length_constructor) { - { - multi_span s{nullptr, 0}; - CHECK(s.length() == 0 && s.data() == nullptr); - - multi_span cs{nullptr, 0}; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - - { - multi_span s{nullptr, 0}; - CHECK(s.length() == 0 && s.data() == nullptr); - - multi_span cs{nullptr, 0}; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - - { #ifdef CONFIRM_COMPILATION_ERRORS - multi_span s{nullptr, 0}; - CHECK(s.length() == 1 && s.data() == nullptr); // explains why it can't compile + multi_span s; + CHECK((s.length() == 1 && s.data() == nullptr)); // explains why it can't compile #endif - } - - { - auto workaround_macro = []() { multi_span s{nullptr, 1}; }; - CHECK_THROW(workaround_macro(), fail_fast); - - auto const_workaround_macro = []() { multi_span cs{nullptr, 1}; }; - CHECK_THROW(const_workaround_macro(), fail_fast); - } - - { - auto workaround_macro = []() { multi_span s{nullptr, 1}; }; - CHECK_THROW(workaround_macro(), fail_fast); - - auto const_workaround_macro = []() { multi_span s{nullptr, 1}; }; - CHECK_THROW(const_workaround_macro(), fail_fast); - } - - { - multi_span s{nullptr, 0}; - CHECK(s.length() == 0 && s.data() == nullptr); - - multi_span cs{nullptr, 0}; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } } - TEST(from_element_constructor) { - int i = 5; + multi_span s{}; + CHECK((s.length() == 0 && s.data() == nullptr)); - { - multi_span s = i; - CHECK(s.length() == 1 && s.data() == &i); - CHECK(s[0] == 5); + multi_span cs{}; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } +} - multi_span cs = i; - CHECK(cs.length() == 1 && cs.data() == &i); - CHECK(cs[0] == 5); - } +TEST_CASE("from_nullptr_constructor") +{ + { + multi_span s = nullptr; + CHECK((s.length() == 0 && s.data() == nullptr)); - { -#ifdef CONFIRM_COMPILATION_ERRORS - const j = 1; - multi_span s = j; -#endif - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s = i; - CHECK(s.length() == 0 && s.data() == &i); -#endif - } - - { - multi_span s = i; - CHECK(s.length() == 1 && s.data() == &i); - CHECK(s[0] == 5); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s = i; - CHECK(s.length() == 2 && s.data() == &i); -#endif - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - auto get_a_temp = []() -> int { return 4; }; - auto use_a_span = [](multi_span s) { (void) s; }; - use_a_span(get_a_temp()); -#endif - } + multi_span cs = nullptr; + CHECK((cs.length() == 0 && cs.data() == nullptr)); } - TEST(from_pointer_length_constructor) { - int arr[4] = {1, 2, 3, 4}; + multi_span s = nullptr; + CHECK((s.length() == 0 && s.data() == nullptr)); - { - multi_span s{&arr[0], 2}; - CHECK(s.length() == 2 && s.data() == &arr[0]); - CHECK(s[0] == 1 && s[1] == 2); - } - - { - multi_span s{&arr[0], 2}; - CHECK(s.length() == 2 && s.data() == &arr[0]); - CHECK(s[0] == 1 && s[1] == 2); - } - - { - int* p = nullptr; - multi_span s{p, 0}; - CHECK(s.length() == 0 && s.data() == nullptr); - } - - { - int* p = nullptr; - auto workaround_macro = [=]() { multi_span s{p, 2}; }; - CHECK_THROW(workaround_macro(), fail_fast); - } + multi_span cs = nullptr; + CHECK((cs.length() == 0 && cs.data() == nullptr)); } - TEST(from_pointer_pointer_constructor) { - int arr[4] = {1, 2, 3, 4}; - - { - multi_span s{&arr[0], &arr[2]}; - CHECK(s.length() == 2 && s.data() == &arr[0]); - CHECK(s[0] == 1 && s[1] == 2); - } - - { - multi_span s{&arr[0], &arr[2]}; - CHECK(s.length() == 2 && s.data() == &arr[0]); - CHECK(s[0] == 1 && s[1] == 2); - } - - { - multi_span s{&arr[0], &arr[0]}; - CHECK(s.length() == 0 && s.data() == &arr[0]); - } - - { - multi_span s{&arr[0], &arr[0]}; - CHECK(s.length() == 0 && s.data() == &arr[0]); - } - - { - auto workaround_macro = [&]() { multi_span s{&arr[1], &arr[0]}; }; - CHECK_THROW(workaround_macro(), fail_fast); - } - - { - int* p = nullptr; - auto workaround_macro = [&]() { multi_span s{&arr[0], p}; }; - CHECK_THROW(workaround_macro(), fail_fast); - } - - { - int* p = nullptr; - auto workaround_macro = [&]() { multi_span s{p, p}; }; - CHECK_THROW(workaround_macro(), fail_fast); - } - - { - int* p = nullptr; - auto workaround_macro = [&]() { multi_span s{&arr[0], p}; }; - CHECK_THROW(workaround_macro(), fail_fast); - } +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s = nullptr; + CHECK((s.length() == 1 && s.data() == nullptr)); // explains why it can't compile +#endif } - TEST(from_array_constructor) { - int arr[5] = {1, 2, 3, 4, 5}; + multi_span s{nullptr}; + CHECK((s.length() == 0 && s.data() == nullptr)); - { - multi_span s{arr}; - CHECK(s.length() == 5 && s.data() == &arr[0]); - } - - { - multi_span s{arr}; - CHECK(s.length() == 5 && s.data() == &arr[0]); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s{arr}; -#endif - } - - { - multi_span s{arr}; - CHECK(s.length() == 0 && s.data() == &arr[0]); - } - - int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; - - { - multi_span s{arr2d}; - CHECK(s.length() == 6 && s.data() == &arr2d[0][0]); - CHECK(s[0] == 1 && s[5] == 6); - } - - { - multi_span s{arr2d}; - CHECK(s.length() == 0 && s.data() == &arr2d[0][0]); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s{arr2d}; -#endif - } - - { - multi_span s{arr2d}; - CHECK(s.length() == 6 && s.data() == &arr2d[0][0]); - CHECK(s[0] == 1 && s[5] == 6); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s{arr2d}; -#endif - } - - { - multi_span s{arr2d[0]}; - CHECK(s.length() == 1 && s.data() == &arr2d[0]); - } - - { - multi_span s{arr2d}; - CHECK(s.length() == 6 && s.data() == &arr2d[0][0]); - auto workaround_macro = [&]() { return s[{1, 2}] == 6; }; - CHECK(workaround_macro()); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s{arr2d}; -#endif - } - - int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - - { - multi_span s{arr3d}; - CHECK(s.length() == 12 && s.data() == &arr3d[0][0][0]); - CHECK(s[0] == 1 && s[11] == 12); - } - - { - multi_span s{arr3d}; - CHECK(s.length() == 0 && s.data() == &arr3d[0][0][0]); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s{arr3d}; -#endif - } - - { - multi_span s{arr3d}; - CHECK(s.length() == 12 && s.data() == &arr3d[0][0][0]); - CHECK(s[0] == 1 && s[5] == 6); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s{arr3d}; -#endif - } - - { - multi_span s{arr3d[0]}; - CHECK(s.length() == 1 && s.data() == &arr3d[0]); - } - - { - multi_span s{arr3d}; - CHECK(s.length() == 12 && s.data() == &arr3d[0][0][0]); - auto workaround_macro = [&]() { return s[{2, 1, 0}] == 11; }; - CHECK(workaround_macro()); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s{arr3d}; -#endif - } + multi_span cs{nullptr}; + CHECK((cs.length() == 0 && cs.data() == nullptr)); } - TEST(from_dynamic_array_constructor) { - double(*arr)[3][4] = new double[100][3][4]; + multi_span s{nullptr}; + CHECK((s.length() == 0 && s.data() == nullptr)); - { - multi_span s(arr, 10); - CHECK(s.length() == 120 && s.data() == &arr[0][0][0]); - CHECK_THROW(s[10][3][4], fail_fast); - } + multi_span cs{nullptr}; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } +} - { - multi_span s(arr, 10); - CHECK(s.length() == 120 && s.data() == &arr[0][0][0]); - } +TEST_CASE("from_nullptr_length_constructor") +{ + { + multi_span s{nullptr, 0}; + CHECK((s.length() == 0 && s.data() == nullptr)); - { - multi_span s(arr, 10); - CHECK(s.length() == 120 && s.data() == &arr[0][0][0]); - } + multi_span cs{nullptr, 0}; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } - { - multi_span s(arr, 0); - CHECK(s.length() == 0 && s.data() == &arr[0][0][0]); + { + multi_span s{nullptr, 0}; + CHECK((s.length() == 0 && s.data() == nullptr)); + + multi_span cs{nullptr, 0}; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s{nullptr, 0}; + CHECK((s.length() == 1 && s.data() == nullptr)); // explains why it can't compile +#endif + } + + { + auto workaround_macro = []() { multi_span s{nullptr, 1}; }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + + auto const_workaround_macro = []() { multi_span cs{nullptr, 1}; }; + CHECK_THROWS_AS(const_workaround_macro(), fail_fast); + } + + { + auto workaround_macro = []() { multi_span s{nullptr, 1}; }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + + auto const_workaround_macro = []() { multi_span s{nullptr, 1}; }; + CHECK_THROWS_AS(const_workaround_macro(), fail_fast); + } + + { + multi_span s{nullptr, 0}; + CHECK((s.length() == 0 && s.data() == nullptr)); + + multi_span cs{nullptr, 0}; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } +} + +TEST_CASE("from_element_constructor") +{ + int i = 5; + + { + multi_span s = i; + CHECK((s.length() == 1 && s.data() == &i)); + CHECK(s[0] == 5); + + multi_span cs = i; + CHECK((cs.length() == 1 && cs.data() == &i)); + CHECK(cs[0] == 5); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + const j = 1; + multi_span s = j; +#endif + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s = i; + CHECK((s.length() == 0 && s.data() == &i)); +#endif + } + + { + multi_span s = i; + CHECK((s.length() == 1 && s.data() == &i)); + CHECK(s[0] == 5); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s = i; + CHECK((s.length() == 2 && s.data() == &i)); +#endif + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_a_temp = []() -> int { return 4; }; + auto use_a_span = [](multi_span s) { (void) s; }; + use_a_span(get_a_temp()); +#endif + } +} + +TEST_CASE("from_pointer_length_constructor") +{ + int arr[4] = {1, 2, 3, 4}; + + { + multi_span s{&arr[0], 2}; + CHECK((s.length() == 2 && s.data() == &arr[0])); + CHECK((s[0] == 1 && s[1] == 2)); + } + + { + multi_span s{&arr[0], 2}; + CHECK((s.length() == 2 && s.data() == &arr[0])); + CHECK((s[0] == 1 && s[1] == 2)); + } + + { + int* p = nullptr; + multi_span s{p, 0}; + CHECK((s.length() == 0 && s.data() == nullptr)); + } + + { + int* p = nullptr; + auto workaround_macro = [=]() { multi_span s{p, 2}; }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } +} + +TEST_CASE("from_pointer_pointer_constructor") +{ + int arr[4] = {1, 2, 3, 4}; + + { + multi_span s{&arr[0], &arr[2]}; + CHECK((s.length() == 2 && s.data() == &arr[0])); + CHECK((s[0] == 1 && s[1] == 2)); + } + + { + multi_span s{&arr[0], &arr[2]}; + CHECK((s.length() == 2 && s.data() == &arr[0])); + CHECK((s[0] == 1 && s[1] == 2)); + } + + { + multi_span s{&arr[0], &arr[0]}; + CHECK((s.length() == 0 && s.data() == &arr[0])); + } + + { + multi_span s{&arr[0], &arr[0]}; + CHECK((s.length() == 0 && s.data() == &arr[0])); + } + + { + auto workaround_macro = [&]() { multi_span s{&arr[1], &arr[0]}; }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } + + { + int* p = nullptr; + auto workaround_macro = [&]() { multi_span s{&arr[0], p}; }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } + + { + int* p = nullptr; + auto workaround_macro = [&]() { multi_span s{p, p}; }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } + + { + int* p = nullptr; + auto workaround_macro = [&]() { multi_span s{&arr[0], p}; }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } +} + +TEST_CASE("from_array_constructor") +{ + int arr[5] = {1, 2, 3, 4, 5}; + + { + multi_span s{arr}; + CHECK((s.length() == 5 && s.data() == &arr[0])); + } + + { + multi_span s{arr}; + CHECK((s.length() == 5 && s.data() == &arr[0])); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s{arr}; +#endif + } + + { + multi_span s{arr}; + CHECK((s.length() == 0 && s.data() == &arr[0])); + } + + int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; + + { + multi_span s{arr2d}; + CHECK((s.length() == 6 && s.data() == &arr2d[0][0])); + CHECK((s[0] == 1 && s[5] == 6)); + } + + { + multi_span s{arr2d}; + CHECK((s.length() == 0 && s.data() == &arr2d[0][0])); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s{arr2d}; +#endif + } + + { + multi_span s{arr2d}; + CHECK((s.length() == 6 && s.data() == &arr2d[0][0])); + CHECK((s[0] == 1 && s[5] == 6)); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s{arr2d}; +#endif + } + + { + multi_span s{arr2d[0]}; + CHECK((s.length() == 1 && s.data() == &arr2d[0])); + } + + { + multi_span s{arr2d}; + CHECK((s.length() == 6 && s.data() == &arr2d[0][0])); + auto workaround_macro = [&]() { return s[{1, 2}] == 6; }; + CHECK(workaround_macro()); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s{arr2d}; +#endif + } + + int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + + { + multi_span s{arr3d}; + CHECK((s.length() == 12 && s.data() == &arr3d[0][0][0])); + CHECK((s[0] == 1 && s[11] == 12)); + } + + { + multi_span s{arr3d}; + CHECK((s.length() == 0 && s.data() == &arr3d[0][0][0])); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s{arr3d}; +#endif + } + + { + multi_span s{arr3d}; + CHECK((s.length() == 12 && s.data() == &arr3d[0][0][0])); + CHECK((s[0] == 1 && s[5] == 6)); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s{arr3d}; +#endif + } + + { + multi_span s{arr3d[0]}; + CHECK((s.length() == 1 && s.data() == &arr3d[0])); + } + + { + multi_span s{arr3d}; + CHECK((s.length() == 12 && s.data() == &arr3d[0][0][0])); + auto workaround_macro = [&]() { return s[{2, 1, 0}] == 11; }; + CHECK(workaround_macro()); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s{arr3d}; +#endif + } +} + +TEST_CASE("from_dynamic_array_constructor") +{ + double(*arr)[3][4] = new double[100][3][4]; + + { + multi_span s(arr, 10); + CHECK((s.length() == 120 && s.data() == &arr[0][0][0])); + CHECK_THROWS_AS(s[10][3][4], fail_fast); + } + + { + multi_span s(arr, 10); + CHECK((s.length() == 120 && s.data() == &arr[0][0][0])); + } + + { + multi_span s(arr, 10); + CHECK((s.length() == 120 && s.data() == &arr[0][0][0])); + } + + { + multi_span s(arr, 0); + CHECK((s.length() == 0 && s.data() == &arr[0][0][0])); + } + + delete[] arr; +} + +TEST_CASE("from_std_array_constructor") +{ + std::array arr = {1, 2, 3, 4}; + + { + multi_span s{arr}; + CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); + + multi_span cs{arr}; + CHECK((cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data())); + } + + { + multi_span s{arr}; + CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); + + multi_span cs{arr}; + CHECK((cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data())); + } + + { + multi_span s{arr}; + CHECK((s.size() == 2 && s.data() == arr.data())); + + multi_span cs{arr}; + CHECK((cs.size() == 2 && cs.data() == arr.data())); + } + + { + multi_span s{arr}; + CHECK((s.size() == 0 && s.data() == arr.data())); + + multi_span cs{arr}; + CHECK((cs.size() == 0 && cs.data() == arr.data())); + } + + // TODO This is currently an unsupported scenario. We will come back to it as we revise + // the multidimensional interface and what transformations between dimensionality look like + //{ + // multi_span s{arr}; + // CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); + //} + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s{arr}; +#endif + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_an_array = []() { return std::array{1, 2, 3, 4}; }; + auto take_a_span = [](multi_span s) { (void) s; }; + // try to take a temporary std::array + take_a_span(get_an_array()); +#endif + } +} + +TEST_CASE("from_const_std_array_constructor") +{ + const std::array arr = {1, 2, 3, 4}; + + { + multi_span s{arr}; + CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); + } + + { + multi_span s{arr}; + CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); + } + + { + multi_span s{arr}; + CHECK((s.size() == 2 && s.data() == arr.data())); + } + + { + multi_span s{arr}; + CHECK((s.size() == 0 && s.data() == arr.data())); + } + + // TODO This is currently an unsupported scenario. We will come back to it as we revise + // the multidimensional interface and what transformations between dimensionality look like + //{ + // multi_span s{arr}; + // CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); + //} + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s{arr}; +#endif + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_an_array = []() -> const std::array { return {1, 2, 3, 4}; }; + auto take_a_span = [](multi_span s) { (void) s; }; + // try to take a temporary std::array + take_a_span(get_an_array()); +#endif + } +} + +TEST_CASE("from_container_constructor") +{ + std::vector v = {1, 2, 3}; + const std::vector cv = v; + + { + multi_span s{v}; + CHECK((s.size() == narrow_cast(v.size()) && s.data() == v.data())); + + multi_span cs{v}; + CHECK((cs.size() == narrow_cast(v.size()) && cs.data() == v.data())); + } + + std::string str = "hello"; + const std::string cstr = "hello"; + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s{str}; + CHECK((s.size() == narrow_cast(str.size()) && s.data() == str.data())); +#endif + multi_span cs{str}; + CHECK((cs.size() == narrow_cast(str.size()) && cs.data() == str.data())); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s{cstr}; +#endif + multi_span cs{cstr}; + CHECK((cs.size() == narrow_cast(cstr.size()) && + cs.data() == cstr.data())); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_temp_vector = []() -> std::vector { return {}; }; + auto use_span = [](multi_span s) { (void) s; }; + use_span(get_temp_vector()); +#endif + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_temp_string = []() -> std::string { return {}; }; + auto use_span = [](multi_span s) { (void) s; }; + use_span(get_temp_string()); +#endif + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_temp_vector = []() -> const std::vector { return {}; }; + auto use_span = [](multi_span s) { (void) s; }; + use_span(get_temp_vector()); +#endif + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_temp_string = []() -> const std::string { return {}; }; + auto use_span = [](multi_span s) { (void) s; }; + use_span(get_temp_string()); +#endif + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::map m; + multi_span s{m}; +#endif + } +} + +TEST_CASE("from_convertible_span_constructor") +{ +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span av1(nullptr, b1); + + auto f = [&]() { multi_span av1(nullptr); }; + CHECK_THROWS_AS(f(), fail_fast); +#endif + +#ifdef CONFIRM_COMPILATION_ERRORS + static_bounds b12(b11); + b12 = b11; + b11 = b12; + + multi_span av1 = nullptr; + multi_span av2(av1); + multi_span av2(av1); +#endif + + multi_span avd; +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span avb = avd; +#endif + multi_span avcd = avd; + (void) avcd; +} + +TEST_CASE("copy_move_and_assignment") +{ + multi_span s1; + CHECK(s1.empty()); + + int arr[] = {3, 4, 5}; + + multi_span s2 = arr; + CHECK((s2.length() == 3 && s2.data() == &arr[0])); + + s2 = s1; + CHECK(s2.empty()); + + auto get_temp_span = [&]() -> multi_span { return {&arr[1], 2}; }; + auto use_span = [&](multi_span s) { + CHECK((s.length() == 2 && s.data() == &arr[1])); + }; + use_span(get_temp_span()); + + s1 = get_temp_span(); + CHECK((s1.length() == 2 && s1.data() == &arr[1])); +} + +template +void fn(const Bounds&) +{ + static_assert(Bounds::static_size == 60, "static bounds is wrong size"); +} +TEST_CASE("as_multi_span_reshape") +{ + int a[3][4][5]; + auto av = as_multi_span(a); + fn(av.bounds()); + auto av2 = as_multi_span(av, dim<60>()); + auto av3 = as_multi_span(av2, dim<3>(), dim<4>(), dim<5>()); + auto av4 = as_multi_span(av3, dim<4>(), dim(3), dim<5>()); + auto av5 = as_multi_span(av4, dim<3>(), dim<4>(), dim<5>()); + auto av6 = as_multi_span(av5, dim<12>(), dim(5)); + + fill(av6.begin(), av6.end(), 1); + + auto av7 = as_bytes(av6); + + auto av8 = as_multi_span(av7); + + CHECK(av8.size() == av6.size()); + for (auto i = 0; i < av8.size(); i++) { + CHECK(av8[i] == 1); + } +} + +TEST_CASE("first") +{ + int arr[5] = {1, 2, 3, 4, 5}; + + { + multi_span av = arr; + CHECK((av.first<2>().bounds() == static_bounds<2>())); + CHECK(av.first<2>().length() == 2); + CHECK(av.first(2).length() == 2); + } + + { + multi_span av = arr; + CHECK((av.first<0>().bounds() == static_bounds<0>())); + CHECK(av.first<0>().length() == 0); + CHECK(av.first(0).length() == 0); + } + + { + multi_span av = arr; + CHECK((av.first<5>().bounds() == static_bounds<5>())); + CHECK(av.first<5>().length() == 5); + CHECK(av.first(5).length() == 5); + } + + { + multi_span av = arr; +#ifdef CONFIRM_COMPILATION_ERRORS + CHECK(av.first<6>().bounds() == static_bounds<6>()); + CHECK(av.first<6>().length() == 6); + CHECK(av.first<-1>().length() == -1); +#endif + CHECK_THROWS_AS(av.first(6).length(), fail_fast); + } + + { + multi_span av; + CHECK((av.first<0>().bounds() == static_bounds<0>())); + CHECK(av.first<0>().length() == 0); + CHECK(av.first(0).length() == 0); + } +} + +TEST_CASE("last") +{ + int arr[5] = {1, 2, 3, 4, 5}; + + { + multi_span av = arr; + CHECK((av.last<2>().bounds() == static_bounds<2>())); + CHECK(av.last<2>().length() == 2); + CHECK(av.last(2).length() == 2); + } + + { + multi_span av = arr; + CHECK((av.last<0>().bounds() == static_bounds<0>())); + CHECK(av.last<0>().length() == 0); + CHECK(av.last(0).length() == 0); + } + + { + multi_span av = arr; + CHECK((av.last<5>().bounds() == static_bounds<5>())); + CHECK(av.last<5>().length() == 5); + CHECK(av.last(5).length() == 5); + } + + { + multi_span av = arr; +#ifdef CONFIRM_COMPILATION_ERRORS + CHECK((av.last<6>().bounds() == static_bounds<6>())); + CHECK(av.last<6>().length() == 6); +#endif + CHECK_THROWS_AS(av.last(6).length(), fail_fast); + } + + { + multi_span av; + CHECK((av.last<0>().bounds() == static_bounds<0>())); + CHECK(av.last<0>().length() == 0); + CHECK(av.last(0).length() == 0); + } +} + +TEST_CASE("subspan") +{ + int arr[5] = {1, 2, 3, 4, 5}; + + { + multi_span av = arr; + CHECK((av.subspan<2, 2>().bounds() == static_bounds<2>())); + CHECK((av.subspan<2, 2>().length() == 2)); + CHECK(av.subspan(2, 2).length() == 2); + CHECK(av.subspan(2, 3).length() == 3); + } + + { + multi_span av = arr; + CHECK((av.subspan<0, 0>().bounds() == static_bounds<0>())); + CHECK((av.subspan<0, 0>().length() == 0)); + CHECK(av.subspan(0, 0).length() == 0); + } + + { + multi_span av = arr; + CHECK((av.subspan<0, 5>().bounds() == static_bounds<5>())); + CHECK((av.subspan<0, 5>().length() == 5)); + CHECK(av.subspan(0, 5).length() == 5); + CHECK_THROWS_AS(av.subspan(0, 6).length(), fail_fast); + CHECK_THROWS_AS(av.subspan(1, 5).length(), fail_fast); + } + + { + multi_span av = arr; + CHECK((av.subspan<5, 0>().bounds() == static_bounds<0>())); + CHECK((av.subspan<5, 0>().length() == 0)); + CHECK(av.subspan(5, 0).length() == 0); + CHECK_THROWS_AS(av.subspan(6, 0).length(), fail_fast); + } + + { + multi_span av; + CHECK((av.subspan<0, 0>().bounds() == static_bounds<0>())); + CHECK((av.subspan<0, 0>().length() == 0)); + CHECK(av.subspan(0, 0).length() == 0); + CHECK_THROWS_AS((av.subspan<1, 0>().length()), fail_fast); + } + + { + multi_span av; + CHECK(av.subspan(0).length() == 0); + CHECK_THROWS_AS(av.subspan(1).length(), fail_fast); + } + + { + multi_span av = arr; + CHECK(av.subspan(0).length() == 5); + CHECK(av.subspan(1).length() == 4); + CHECK(av.subspan(4).length() == 1); + CHECK(av.subspan(5).length() == 0); + CHECK_THROWS_AS(av.subspan(6).length(), fail_fast); + auto av2 = av.subspan(1); + for (int i = 0; i < 4; ++i) CHECK(av2[i] == i + 2); + } + + { + multi_span av = arr; + CHECK(av.subspan(0).length() == 5); + CHECK(av.subspan(1).length() == 4); + CHECK(av.subspan(4).length() == 1); + CHECK(av.subspan(5).length() == 0); + CHECK_THROWS_AS(av.subspan(6).length(), fail_fast); + auto av2 = av.subspan(1); + for (int i = 0; i < 4; ++i) CHECK(av2[i] == i + 2); + } +} + +TEST_CASE("rank") +{ + int arr[2] = {1, 2}; + + { + multi_span s; + CHECK(s.rank() == 1); + } + + { + multi_span s = arr; + CHECK(s.rank() == 1); + } + + int arr2d[1][1] = {}; + { + multi_span s = arr2d; + CHECK(s.rank() == 2); + } +} + +TEST_CASE("extent") +{ + { + multi_span s; + CHECK(s.extent() == 0); + CHECK(s.extent(0) == 0); + CHECK_THROWS_AS(s.extent(1), fail_fast); +#ifdef CONFIRM_COMPILATION_ERRORS + CHECK(s.extent<1>() == 0); +#endif + } + + { + multi_span s; + CHECK(s.extent() == 0); + CHECK(s.extent(0) == 0); + CHECK_THROWS_AS(s.extent(1), fail_fast); + } + + { + int arr2d[1][2] = {}; + + multi_span s = arr2d; + CHECK(s.extent() == 1); + CHECK(s.extent<0>() == 1); + CHECK(s.extent<1>() == 2); + CHECK(s.extent(0) == 1); + CHECK(s.extent(1) == 2); + CHECK_THROWS_AS(s.extent(3), fail_fast); + } + + { + int arr2d[1][2] = {}; + + multi_span s = arr2d; + CHECK(s.extent() == 0); + CHECK(s.extent<0>() == 0); + CHECK(s.extent<1>() == 2); + CHECK(s.extent(0) == 0); + CHECK(s.extent(1) == 2); + CHECK_THROWS_AS(s.extent(3), fail_fast); + } +} + +TEST_CASE("operator_function_call") +{ + int arr[4] = {1, 2, 3, 4}; + + { + multi_span s = arr; + CHECK(s(0) == 1); + CHECK_THROWS_AS(s(5), fail_fast); + } + + int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; + + { + multi_span s = arr2d; + CHECK(s(0, 0) == 1); + CHECK(s(0, 1) == 2); + CHECK(s(1, 2) == 6); + } + + int arr3d[2][2][2] = {1, 2, 3, 4, 5, 6, 7, 8}; + + { + multi_span s = arr3d; + CHECK(s(0, 0, 0) == 1); + CHECK(s(1, 1, 1) == 8); + } +} + +TEST_CASE("comparison_operators") +{ + { + int arr[10][2]; + auto s1 = as_multi_span(arr); + multi_span s2 = s1; + + CHECK(s1 == s2); + + multi_span s3 = as_multi_span(s1, dim(20)); + CHECK((s3 == s2 && s3 == s1)); + } + + { + multi_span s1 = nullptr; + multi_span s2 = nullptr; + CHECK(s1 == s2); + CHECK(!(s1 != s2)); + CHECK(!(s1 < s2)); + CHECK(s1 <= s2); + CHECK(!(s1 > s2)); + CHECK(s1 >= s2); + CHECK(s2 == s1); + CHECK(!(s2 != s1)); + CHECK(!(s2 < s1)); + CHECK(s2 <= s1); + CHECK(!(s2 > s1)); + CHECK(s2 >= s1); + } + + { + int arr[] = {2, 1}; // bigger + + multi_span s1 = nullptr; + multi_span s2 = arr; + + CHECK(s1 != s2); + CHECK(s2 != s1); + CHECK(!(s1 == s2)); + CHECK(!(s2 == s1)); + CHECK(s1 < s2); + CHECK(!(s2 < s1)); + CHECK(s1 <= s2); + CHECK(!(s2 <= s1)); + CHECK(s2 > s1); + CHECK(!(s1 > s2)); + CHECK(s2 >= s1); + CHECK(!(s1 >= s2)); + } + + { + int arr1[] = {1, 2}; + int arr2[] = {1, 2}; + multi_span s1 = arr1; + multi_span s2 = arr2; + + CHECK(s1 == s2); + CHECK(!(s1 != s2)); + CHECK(!(s1 < s2)); + CHECK(s1 <= s2); + CHECK(!(s1 > s2)); + CHECK(s1 >= s2); + CHECK(s2 == s1); + CHECK(!(s2 != s1)); + CHECK(!(s2 < s1)); + CHECK(s2 <= s1); + CHECK(!(s2 > s1)); + CHECK(s2 >= s1); + } + + { + int arr[] = {1, 2, 3}; + + multi_span s1 = {&arr[0], 2}; // shorter + multi_span s2 = arr; // longer + + CHECK(s1 != s2); + CHECK(s2 != s1); + CHECK(!(s1 == s2)); + CHECK(!(s2 == s1)); + CHECK(s1 < s2); + CHECK(!(s2 < s1)); + CHECK(s1 <= s2); + CHECK(!(s2 <= s1)); + CHECK(s2 > s1); + CHECK(!(s1 > s2)); + CHECK(s2 >= s1); + CHECK(!(s1 >= s2)); + } + + { + int arr1[] = {1, 2}; // smaller + int arr2[] = {2, 1}; // bigger + + multi_span s1 = arr1; + multi_span s2 = arr2; + + CHECK(s1 != s2); + CHECK(s2 != s1); + CHECK(!(s1 == s2)); + CHECK(!(s2 == s1)); + CHECK(s1 < s2); + CHECK(!(s2 < s1)); + CHECK(s1 <= s2); + CHECK(!(s2 <= s1)); + CHECK(s2 > s1); + CHECK(!(s1 > s2)); + CHECK(s2 >= s1); + CHECK(!(s1 >= s2)); + } +} + +TEST_CASE("basics") +{ + auto ptr = as_multi_span(new int[10], 10); + fill(ptr.begin(), ptr.end(), 99); + for (int num : ptr) { + CHECK(num == 99); + } + + delete[] ptr.data(); +} + +TEST_CASE("bounds_checks") +{ + int arr[10][2]; + auto av = as_multi_span(arr); + + fill(begin(av), end(av), 0); + + av[2][0] = 1; + av[1][1] = 3; + + // out of bounds + CHECK_THROWS_AS(av[1][3] = 3, fail_fast); + CHECK_THROWS_AS((av[{1, 3}] = 3), fail_fast); + + CHECK_THROWS_AS(av[10][2], fail_fast); + CHECK_THROWS_AS((av[{10, 2}]), fail_fast); + + CHECK_THROWS_AS(av[-1][0], fail_fast); + CHECK_THROWS_AS((av[{-1, 0}]), fail_fast); + + CHECK_THROWS_AS(av[0][-1], fail_fast); + CHECK_THROWS_AS((av[{0, -1}]), fail_fast); +} + +void overloaded_func(multi_span exp, int expected_value) +{ + for (auto val : exp) { + CHECK(val == expected_value); + } +} + +void overloaded_func(multi_span exp, char expected_value) +{ + for (auto val : exp) { + CHECK(val == expected_value); + } +} + +void fixed_func(multi_span exp, int expected_value) +{ + for (auto val : exp) { + CHECK(val == expected_value); + } +} + +TEST_CASE("span_parameter_test") +{ + auto data = new int[4][3][5]; + + auto av = as_multi_span(data, 4); + + CHECK(av.size() == 60); + + fill(av.begin(), av.end(), 34); + + int count = 0; + for_each(av.rbegin(), av.rend(), [&](int val) { count += val; }); + CHECK(count == 34 * 60); + overloaded_func(av, 34); + + overloaded_func(as_multi_span(av, dim(4), dim(3), dim(5)), 34); + + // fixed_func(av, 34); + delete[] data; +} + +TEST_CASE("md_access") +{ + auto width = 5, height = 20; + + auto imgSize = width * height; + auto image_ptr = new int[static_cast(imgSize)][3]; + + // size check will be done + auto image_view = + as_multi_span(as_multi_span(image_ptr, imgSize), dim(height), dim(width), dim<3>()); + + iota(image_view.begin(), image_view.end(), 1); + + int expected = 0; + for (auto i = 0; i < height; i++) { + for (auto j = 0; j < width; j++) { + CHECK(expected + 1 == image_view[i][j][0]); + CHECK(expected + 2 == image_view[i][j][1]); + CHECK(expected + 3 == image_view[i][j][2]); + + auto val = image_view[{i, j, 0}]; + CHECK(expected + 1 == val); + val = image_view[{i, j, 1}]; + CHECK(expected + 2 == val); + val = image_view[{i, j, 2}]; + CHECK(expected + 3 == val); + + expected += 3; } + } +} + +TEST_CASE("as_multi_span") +{ + { + int* arr = new int[150]; + + auto av = as_multi_span(arr, dim<10>(), dim(3), dim<5>()); + + fill(av.begin(), av.end(), 24); + overloaded_func(av, 24); delete[] arr; + + array stdarr{0}; + auto av2 = as_multi_span(stdarr); + overloaded_func(as_multi_span(av2, dim(1), dim<3>(), dim<5>()), 0); + + string str = "ttttttttttttttt"; // size = 15 + auto t = str.data(); + (void) t; + auto av3 = as_multi_span(str); + overloaded_func(as_multi_span(av3, dim(1), dim<3>(), dim<5>()), 't'); } - TEST(from_std_array_constructor) { - std::array arr = {1, 2, 3, 4}; - - { - multi_span s{arr}; - CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - - multi_span cs{arr}; - CHECK(cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data()); - } - - { - multi_span s{arr}; - CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - - multi_span cs{arr}; - CHECK(cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data()); - } - - { - multi_span s{arr}; - CHECK(s.size() == 2 && s.data() == arr.data()); - - multi_span cs{arr}; - CHECK(cs.size() == 2 && cs.data() == arr.data()); - } - - { - multi_span s{arr}; - CHECK(s.size() == 0 && s.data() == arr.data()); - - multi_span cs{arr}; - CHECK(cs.size() == 0 && cs.data() == arr.data()); - } - - // TODO This is currently an unsupported scenario. We will come back to it as we revise - // the multidimensional interface and what transformations between dimensionality look like - //{ - // multi_span s{arr}; - // CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - //} - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s{arr}; -#endif - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - auto get_an_array = []() { return std::array{1, 2, 3, 4}; }; - auto take_a_span = [](multi_span s) { (void) s; }; - // try to take a temporary std::array - take_a_span(get_an_array()); -#endif - } + string str; + multi_span strspan = as_multi_span(str); + (void) strspan; + const string cstr; + multi_span cstrspan = as_multi_span(cstr); + (void) cstrspan; } - TEST(from_const_std_array_constructor) - { - const std::array arr = {1, 2, 3, 4}; - - { - multi_span s{arr}; - CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - } - - { - multi_span s{arr}; - CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - } - - { - multi_span s{arr}; - CHECK(s.size() == 2 && s.data() == arr.data()); - } - - { - multi_span s{arr}; - CHECK(s.size() == 0 && s.data() == arr.data()); - } - - // TODO This is currently an unsupported scenario. We will come back to it as we revise - // the multidimensional interface and what transformations between dimensionality look like - //{ - // multi_span s{arr}; - // CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - //} - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s{arr}; -#endif - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - auto get_an_array = []() -> const std::array { return {1, 2, 3, 4}; }; - auto take_a_span = [](multi_span s) { (void) s; }; - // try to take a temporary std::array - take_a_span(get_an_array()); -#endif - } - } - - TEST(from_container_constructor) - { - std::vector v = {1, 2, 3}; - const std::vector cv = v; - - { - multi_span s{v}; - CHECK(s.size() == narrow_cast(v.size()) && s.data() == v.data()); - - multi_span cs{v}; - CHECK(cs.size() == narrow_cast(v.size()) && cs.data() == v.data()); - } - - std::string str = "hello"; - const std::string cstr = "hello"; - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s{str}; - CHECK(s.size() == narrow_cast(str.size()) && s.data() == str.data()); -#endif - multi_span cs{str}; - CHECK(cs.size() == narrow_cast(str.size()) && cs.data() == str.data()); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s{cstr}; -#endif - multi_span cs{cstr}; - CHECK(cs.size() == narrow_cast(cstr.size()) && - cs.data() == cstr.data()); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - auto get_temp_vector = []() -> std::vector { return {}; }; - auto use_span = [](multi_span s) { (void) s; }; - use_span(get_temp_vector()); -#endif - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - auto get_temp_string = []() -> std::string { return {}; }; - auto use_span = [](multi_span s) { (void) s; }; - use_span(get_temp_string()); -#endif - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - auto get_temp_vector = []() -> const std::vector { return {}; }; - auto use_span = [](multi_span s) { (void) s; }; - use_span(get_temp_vector()); -#endif - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - auto get_temp_string = []() -> const std::string { return {}; }; - auto use_span = [](multi_span s) { (void) s; }; - use_span(get_temp_string()); -#endif - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - std::map m; - multi_span s{m}; -#endif - } - } - - TEST(from_convertible_span_constructor) - { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span av1(nullptr, b1); - - auto f = [&]() { multi_span av1(nullptr); }; - CHECK_THROW(f(), fail_fast); -#endif - -#ifdef CONFIRM_COMPILATION_ERRORS - static_bounds b12(b11); - b12 = b11; - b11 = b12; - - multi_span av1 = nullptr; - multi_span av2(av1); - multi_span av2(av1); -#endif - - multi_span avd; -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span avb = avd; -#endif - multi_span avcd = avd; - (void) avcd; - } - - TEST(copy_move_and_assignment) - { - multi_span s1; - CHECK(s1.empty()); - - int arr[] = {3, 4, 5}; - - multi_span s2 = arr; - CHECK(s2.length() == 3 && s2.data() == &arr[0]); - - s2 = s1; - CHECK(s2.empty()); - - auto get_temp_span = [&]() -> multi_span { return {&arr[1], 2}; }; - auto use_span = [&](multi_span s) { - CHECK(s.length() == 2 && s.data() == &arr[1]); - }; - use_span(get_temp_span()); - - s1 = get_temp_span(); - CHECK(s1.length() == 2 && s1.data() == &arr[1]); - } - - template - void fn(const Bounds&) - { - static_assert(Bounds::static_size == 60, "static bounds is wrong size"); - } - TEST(as_multi_span_reshape) { int a[3][4][5]; auto av = as_multi_span(a); - fn(av.bounds()); - auto av2 = as_multi_span(av, dim<60>()); - auto av3 = as_multi_span(av2, dim<3>(), dim<4>(), dim<5>()); - auto av4 = as_multi_span(av3, dim<4>(), dim(3), dim<5>()); - auto av5 = as_multi_span(av4, dim<3>(), dim<4>(), dim<5>()); - auto av6 = as_multi_span(av5, dim<12>(), dim(5)); + const int(*b)[4][5]; + b = a; + auto bv = as_multi_span(b, 3); - fill(av6.begin(), av6.end(), 1); + CHECK(av == bv); - auto av7 = as_bytes(av6); + const std::array arr = {0.0, 0.0, 0.0}; + auto cv = as_multi_span(arr); + (void) cv; - auto av8 = as_multi_span(av7); - - CHECK(av8.size() == av6.size()); - for (auto i = 0; i < av8.size(); i++) { - CHECK(av8[i] == 1); - } - } - - TEST(first) - { - int arr[5] = {1, 2, 3, 4, 5}; - - { - multi_span av = arr; - CHECK((av.first<2>().bounds() == static_bounds<2>())); - CHECK(av.first<2>().length() == 2); - CHECK(av.first(2).length() == 2); - } - - { - multi_span av = arr; - CHECK((av.first<0>().bounds() == static_bounds<0>())); - CHECK(av.first<0>().length() == 0); - CHECK(av.first(0).length() == 0); - } - - { - multi_span av = arr; - CHECK((av.first<5>().bounds() == static_bounds<5>())); - CHECK(av.first<5>().length() == 5); - CHECK(av.first(5).length() == 5); - } - - { - multi_span av = arr; -#ifdef CONFIRM_COMPILATION_ERRORS - CHECK(av.first<6>().bounds() == static_bounds<6>()); - CHECK(av.first<6>().length() == 6); - CHECK(av.first<-1>().length() == -1); -#endif - CHECK_THROW(av.first(6).length(), fail_fast); - } - - { - multi_span av; - CHECK((av.first<0>().bounds() == static_bounds<0>())); - CHECK(av.first<0>().length() == 0); - CHECK(av.first(0).length() == 0); - } - } - - TEST(last) - { - int arr[5] = {1, 2, 3, 4, 5}; - - { - multi_span av = arr; - CHECK((av.last<2>().bounds() == static_bounds<2>())); - CHECK(av.last<2>().length() == 2); - CHECK(av.last(2).length() == 2); - } - - { - multi_span av = arr; - CHECK((av.last<0>().bounds() == static_bounds<0>())); - CHECK(av.last<0>().length() == 0); - CHECK(av.last(0).length() == 0); - } - - { - multi_span av = arr; - CHECK((av.last<5>().bounds() == static_bounds<5>())); - CHECK(av.last<5>().length() == 5); - CHECK(av.last(5).length() == 5); - } - - { - multi_span av = arr; -#ifdef CONFIRM_COMPILATION_ERRORS - CHECK((av.last<6>().bounds() == static_bounds<6>())); - CHECK(av.last<6>().length() == 6); -#endif - CHECK_THROW(av.last(6).length(), fail_fast); - } - - { - multi_span av; - CHECK((av.last<0>().bounds() == static_bounds<0>())); - CHECK(av.last<0>().length() == 0); - CHECK(av.last(0).length() == 0); - } - } - - TEST(subspan) - { - int arr[5] = {1, 2, 3, 4, 5}; - - { - multi_span av = arr; - CHECK((av.subspan<2, 2>().bounds() == static_bounds<2>())); - CHECK((av.subspan<2, 2>().length() == 2)); - CHECK(av.subspan(2, 2).length() == 2); - CHECK(av.subspan(2, 3).length() == 3); - } - - { - multi_span av = arr; - CHECK((av.subspan<0, 0>().bounds() == static_bounds<0>())); - CHECK((av.subspan<0, 0>().length() == 0)); - CHECK(av.subspan(0, 0).length() == 0); - } - - { - multi_span av = arr; - CHECK((av.subspan<0, 5>().bounds() == static_bounds<5>())); - CHECK((av.subspan<0, 5>().length() == 5)); - CHECK(av.subspan(0, 5).length() == 5); - CHECK_THROW(av.subspan(0, 6).length(), fail_fast); - CHECK_THROW(av.subspan(1, 5).length(), fail_fast); - } - - { - multi_span av = arr; - CHECK((av.subspan<5, 0>().bounds() == static_bounds<0>())); - CHECK((av.subspan<5, 0>().length() == 0)); - CHECK(av.subspan(5, 0).length() == 0); - CHECK_THROW(av.subspan(6, 0).length(), fail_fast); - } - - { - multi_span av; - CHECK((av.subspan<0, 0>().bounds() == static_bounds<0>())); - CHECK((av.subspan<0, 0>().length() == 0)); - CHECK(av.subspan(0, 0).length() == 0); - CHECK_THROW((av.subspan<1, 0>().length()), fail_fast); - } - - { - multi_span av; - CHECK(av.subspan(0).length() == 0); - CHECK_THROW(av.subspan(1).length(), fail_fast); - } - - { - multi_span av = arr; - CHECK(av.subspan(0).length() == 5); - CHECK(av.subspan(1).length() == 4); - CHECK(av.subspan(4).length() == 1); - CHECK(av.subspan(5).length() == 0); - CHECK_THROW(av.subspan(6).length(), fail_fast); - auto av2 = av.subspan(1); - for (int i = 0; i < 4; ++i) CHECK(av2[i] == i + 2); - } - - { - multi_span av = arr; - CHECK(av.subspan(0).length() == 5); - CHECK(av.subspan(1).length() == 4); - CHECK(av.subspan(4).length() == 1); - CHECK(av.subspan(5).length() == 0); - CHECK_THROW(av.subspan(6).length(), fail_fast); - auto av2 = av.subspan(1); - for (int i = 0; i < 4; ++i) CHECK(av2[i] == i + 2); - } - } - - TEST(rank) - { - int arr[2] = {1, 2}; - - { - multi_span s; - CHECK(s.rank() == 1); - } - - { - multi_span s = arr; - CHECK(s.rank() == 1); - } - - int arr2d[1][1] = {}; - { - multi_span s = arr2d; - CHECK(s.rank() == 2); - } - } - - TEST(extent) - { - { - multi_span s; - CHECK(s.extent() == 0); - CHECK(s.extent(0) == 0); - CHECK_THROW(s.extent(1), fail_fast); -#ifdef CONFIRM_COMPILATION_ERRORS - CHECK(s.extent<1>() == 0); -#endif - } - - { - multi_span s; - CHECK(s.extent() == 0); - CHECK(s.extent(0) == 0); - CHECK_THROW(s.extent(1), fail_fast); - } - - { - int arr2d[1][2] = {}; - - multi_span s = arr2d; - CHECK(s.extent() == 1); - CHECK(s.extent<0>() == 1); - CHECK(s.extent<1>() == 2); - CHECK(s.extent(0) == 1); - CHECK(s.extent(1) == 2); - CHECK_THROW(s.extent(3), fail_fast); - } - - { - int arr2d[1][2] = {}; - - multi_span s = arr2d; - CHECK(s.extent() == 0); - CHECK(s.extent<0>() == 0); - CHECK(s.extent<1>() == 2); - CHECK(s.extent(0) == 0); - CHECK(s.extent(1) == 2); - CHECK_THROW(s.extent(3), fail_fast); - } - } - - TEST(operator_function_call) - { - int arr[4] = {1, 2, 3, 4}; - - { - multi_span s = arr; - CHECK(s(0) == 1); - CHECK_THROW(s(5), fail_fast); - } - - int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; - - { - multi_span s = arr2d; - CHECK(s(0, 0) == 1); - CHECK(s(0, 1) == 2); - CHECK(s(1, 2) == 6); - } - - int arr3d[2][2][2] = {1, 2, 3, 4, 5, 6, 7, 8}; - - { - multi_span s = arr3d; - CHECK(s(0, 0, 0) == 1); - CHECK(s(1, 1, 1) == 8); - } - } - - TEST(comparison_operators) - { - { - int arr[10][2]; - auto s1 = as_multi_span(arr); - multi_span s2 = s1; - - CHECK(s1 == s2); - - multi_span s3 = as_multi_span(s1, dim(20)); - CHECK(s3 == s2 && s3 == s1); - } - - { - multi_span s1 = nullptr; - multi_span s2 = nullptr; - CHECK(s1 == s2); - CHECK(!(s1 != s2)); - CHECK(!(s1 < s2)); - CHECK(s1 <= s2); - CHECK(!(s1 > s2)); - CHECK(s1 >= s2); - CHECK(s2 == s1); - CHECK(!(s2 != s1)); - CHECK(!(s2 < s1)); - CHECK(s2 <= s1); - CHECK(!(s2 > s1)); - CHECK(s2 >= s1); - } - - { - int arr[] = {2, 1}; // bigger - - multi_span s1 = nullptr; - multi_span s2 = arr; - - CHECK(s1 != s2); - CHECK(s2 != s1); - CHECK(!(s1 == s2)); - CHECK(!(s2 == s1)); - CHECK(s1 < s2); - CHECK(!(s2 < s1)); - CHECK(s1 <= s2); - CHECK(!(s2 <= s1)); - CHECK(s2 > s1); - CHECK(!(s1 > s2)); - CHECK(s2 >= s1); - CHECK(!(s1 >= s2)); - } - - { - int arr1[] = {1, 2}; - int arr2[] = {1, 2}; - multi_span s1 = arr1; - multi_span s2 = arr2; - - CHECK(s1 == s2); - CHECK(!(s1 != s2)); - CHECK(!(s1 < s2)); - CHECK(s1 <= s2); - CHECK(!(s1 > s2)); - CHECK(s1 >= s2); - CHECK(s2 == s1); - CHECK(!(s2 != s1)); - CHECK(!(s2 < s1)); - CHECK(s2 <= s1); - CHECK(!(s2 > s1)); - CHECK(s2 >= s1); - } - - { - int arr[] = {1, 2, 3}; - - multi_span s1 = {&arr[0], 2}; // shorter - multi_span s2 = arr; // longer - - CHECK(s1 != s2); - CHECK(s2 != s1); - CHECK(!(s1 == s2)); - CHECK(!(s2 == s1)); - CHECK(s1 < s2); - CHECK(!(s2 < s1)); - CHECK(s1 <= s2); - CHECK(!(s2 <= s1)); - CHECK(s2 > s1); - CHECK(!(s1 > s2)); - CHECK(s2 >= s1); - CHECK(!(s1 >= s2)); - } - - { - int arr1[] = {1, 2}; // smaller - int arr2[] = {2, 1}; // bigger - - multi_span s1 = arr1; - multi_span s2 = arr2; - - CHECK(s1 != s2); - CHECK(s2 != s1); - CHECK(!(s1 == s2)); - CHECK(!(s2 == s1)); - CHECK(s1 < s2); - CHECK(!(s2 < s1)); - CHECK(s1 <= s2); - CHECK(!(s2 <= s1)); - CHECK(s2 > s1); - CHECK(!(s1 > s2)); - CHECK(s2 >= s1); - CHECK(!(s1 >= s2)); - } - } - - TEST(basics) - { - auto ptr = as_multi_span(new int[10], 10); - fill(ptr.begin(), ptr.end(), 99); - for (int num : ptr) { - CHECK(num == 99); - } - - delete[] ptr.data(); - } - - TEST(bounds_checks) - { - int arr[10][2]; - auto av = as_multi_span(arr); - - fill(begin(av), end(av), 0); - - av[2][0] = 1; - av[1][1] = 3; - - // out of bounds - CHECK_THROW(av[1][3] = 3, fail_fast); - CHECK_THROW((av[{1, 3}] = 3), fail_fast); - - CHECK_THROW(av[10][2], fail_fast); - CHECK_THROW((av[{10, 2}]), fail_fast); - - CHECK_THROW(av[-1][0], fail_fast); - CHECK_THROW((av[{-1, 0}]), fail_fast); - - CHECK_THROW(av[0][-1], fail_fast); - CHECK_THROW((av[{0, -1}]), fail_fast); - } - - void overloaded_func(multi_span exp, int expected_value) - { - for (auto val : exp) { - CHECK(val == expected_value); - } - } - - void overloaded_func(multi_span exp, char expected_value) - { - for (auto val : exp) { - CHECK(val == expected_value); - } - } - - void fixed_func(multi_span exp, int expected_value) - { - for (auto val : exp) { - CHECK(val == expected_value); - } - } - - TEST(span_parameter_test) - { - auto data = new int[4][3][5]; - - auto av = as_multi_span(data, 4); - - CHECK(av.size() == 60); - - fill(av.begin(), av.end(), 34); - - int count = 0; - for_each(av.rbegin(), av.rend(), [&](int val) { count += val; }); - CHECK(count == 34 * 60); - overloaded_func(av, 34); - - overloaded_func(as_multi_span(av, dim(4), dim(3), dim(5)), 34); - - // fixed_func(av, 34); - delete[] data; - } - - TEST(md_access) - { - auto width = 5, height = 20; - - auto imgSize = width * height; - auto image_ptr = new int[static_cast(imgSize)][3]; - - // size check will be done - auto image_view = - as_multi_span(as_multi_span(image_ptr, imgSize), dim(height), dim(width), dim<3>()); - - iota(image_view.begin(), image_view.end(), 1); - - int expected = 0; - for (auto i = 0; i < height; i++) { - for (auto j = 0; j < width; j++) { - CHECK(expected + 1 == image_view[i][j][0]); - CHECK(expected + 2 == image_view[i][j][1]); - CHECK(expected + 3 == image_view[i][j][2]); - - auto val = image_view[{i, j, 0}]; - CHECK(expected + 1 == val); - val = image_view[{i, j, 1}]; - CHECK(expected + 2 == val); - val = image_view[{i, j, 2}]; - CHECK(expected + 3 == val); - - expected += 3; - } - } - } - - TEST(as_multi_span) - { - { - int* arr = new int[150]; - - auto av = as_multi_span(arr, dim<10>(), dim(3), dim<5>()); - - fill(av.begin(), av.end(), 24); - overloaded_func(av, 24); - - delete[] arr; - - array stdarr{0}; - auto av2 = as_multi_span(stdarr); - overloaded_func(as_multi_span(av2, dim(1), dim<3>(), dim<5>()), 0); - - string str = "ttttttttttttttt"; // size = 15 - auto t = str.data(); - (void) t; - auto av3 = as_multi_span(str); - overloaded_func(as_multi_span(av3, dim(1), dim<3>(), dim<5>()), 't'); - } - - { - string str; - multi_span strspan = as_multi_span(str); - (void) strspan; - const string cstr; - multi_span cstrspan = as_multi_span(cstr); - (void) cstrspan; - } - - { - int a[3][4][5]; - auto av = as_multi_span(a); - const int(*b)[4][5]; - b = a; - auto bv = as_multi_span(b, 3); - - CHECK(av == bv); - - const std::array arr = {0.0, 0.0, 0.0}; - auto cv = as_multi_span(arr); - (void) cv; - - vector vec(3); - auto dv = as_multi_span(vec); - (void) dv; + vector vec(3); + auto dv = as_multi_span(vec); + (void) dv; #ifdef CONFIRM_COMPILATION_ERRORS - auto dv2 = as_multi_span(std::move(vec)); + auto dv2 = as_multi_span(std::move(vec)); #endif - } } - - TEST(empty_spans) - { - { - multi_span empty_av(nullptr); - - CHECK(empty_av.bounds().index_bounds() == index<1>{0}); - CHECK_THROW(empty_av[0], fail_fast); - CHECK_THROW(empty_av.begin()[0], fail_fast); - CHECK_THROW(empty_av.cbegin()[0], fail_fast); - for (auto& v : empty_av) { - (void) v; - CHECK(false); - } - } - - { - multi_span empty_av = {}; - CHECK(empty_av.bounds().index_bounds() == index<1>{0}); - CHECK_THROW(empty_av[0], fail_fast); - CHECK_THROW(empty_av.begin()[0], fail_fast); - CHECK_THROW(empty_av.cbegin()[0], fail_fast); - for (auto& v : empty_av) { - (void) v; - CHECK(false); - } - } - } - - TEST(index_constructor) - { - auto arr = new int[8]; - for (int i = 0; i < 4; ++i) { - arr[2 * i] = 4 + i; - arr[2 * i + 1] = i; - } - - multi_span av(arr, 8); - - ptrdiff_t a[1] = {0}; - index<1> i = a; - - CHECK(av[i] == 4); - - auto av2 = as_multi_span(av, dim<4>(), dim(2)); - ptrdiff_t a2[2] = {0, 1}; - index<2> i2 = a2; - - CHECK(av2[i2] == 0); - CHECK(av2[0][i] == 4); - - delete[] arr; - } - - TEST(index_constructors){{// components of the same type - index<3> i1(0, 1, 2); - CHECK(i1[0] == 0); - - // components of different types - std::size_t c0 = 0; - std::size_t c1 = 1; - index<3> i2(c0, c1, 2); - CHECK(i2[0] == 0); - - // from array - index<3> i3 = {0, 1, 2}; - CHECK(i3[0] == 0); - - // from other index of the same size type - index<3> i4 = i3; - CHECK(i4[0] == 0); - - // default - index<3> i7; - CHECK(i7[0] == 0); - - // default - index<3> i9 = {}; - CHECK(i9[0] == 0); } +TEST_CASE("empty_spans") { - // components of the same type - index<1> i1(0); - CHECK(i1[0] == 0); + { + multi_span empty_av(nullptr); - // components of different types - std::size_t c0 = 0; - index<1> i2(c0); - CHECK(i2[0] == 0); + CHECK(empty_av.bounds().index_bounds() == index<1>{0}); + CHECK_THROWS_AS(empty_av[0], fail_fast); + CHECK_THROWS_AS(empty_av.begin()[0], fail_fast); + CHECK_THROWS_AS(empty_av.cbegin()[0], fail_fast); + for (auto& v : empty_av) { + (void) v; + CHECK(false); + } + } - // from array - index<1> i3 = {0}; - CHECK(i3[0] == 0); - - // from int - index<1> i4 = 0; - CHECK(i4[0] == 0); - - // from other index of the same size type - index<1> i5 = i3; - CHECK(i5[0] == 0); - - // default - index<1> i8; - CHECK(i8[0] == 0); - - // default - index<1> i9 = {}; - CHECK(i9[0] == 0); + { + multi_span empty_av = {}; + CHECK(empty_av.bounds().index_bounds() == index<1>{0}); + CHECK_THROWS_AS(empty_av[0], fail_fast); + CHECK_THROWS_AS(empty_av.begin()[0], fail_fast); + CHECK_THROWS_AS(empty_av.cbegin()[0], fail_fast); + for (auto& v : empty_av) { + (void) v; + CHECK(false); + } + } } -#ifdef CONFIRM_COMPILATION_ERRORS +TEST_CASE("index_constructor") { + auto arr = new int[8]; + for (int i = 0; i < 4; ++i) { + arr[2 * i] = 4 + i; + arr[2 * i + 1] = i; + } + + multi_span av(arr, 8); + + ptrdiff_t a[1] = {0}; + index<1> i = a; + + CHECK(av[i] == 4); + + auto av2 = as_multi_span(av, dim<4>(), dim(2)); + ptrdiff_t a2[2] = {0, 1}; + index<2> i2 = a2; + + CHECK(av2[i2] == 0); + CHECK(av2[0][i] == 4); + + delete[] arr; +} + +TEST_CASE("index_constructors") +{ + { + // components of the same type + index<3> i1(0, 1, 2); + CHECK(i1[0] == 0); + + // components of different types + std::size_t c0 = 0; + std::size_t c1 = 1; + index<3> i2(c0, c1, 2); + CHECK(i2[0] == 0); + + // from array + index<3> i3 = {0, 1, 2}; + CHECK(i3[0] == 0); + + // from other index of the same size type + index<3> i4 = i3; + CHECK(i4[0] == 0); + + // default + index<3> i7; + CHECK(i7[0] == 0); + + // default + index<3> i9 = {}; + CHECK(i9[0] == 0); + } + + { + // components of the same type + index<1> i1(0); + CHECK(i1[0] == 0); + + // components of different types + std::size_t c0 = 0; + index<1> i2(c0); + CHECK(i2[0] == 0); + + // from array + index<1> i3 = {0}; + CHECK(i3[0] == 0); + + // from int + index<1> i4 = 0; + CHECK(i4[0] == 0); + + // from other index of the same size type + index<1> i5 = i3; + CHECK(i5[0] == 0); + + // default + index<1> i8; + CHECK(i8[0] == 0); + + // default + index<1> i9 = {}; + CHECK(i9[0] == 0); + } + + #ifdef CONFIRM_COMPILATION_ERRORS + { index<3> i1(0, 1); index<3> i2(0, 1, 2, 3); index<3> i3 = {0}; index<3> i4 = {0, 1, 2, 3}; index<1> i5 = {0, 1}; -} -#endif + } + #endif } -TEST(index_operations) +TEST_CASE("index_operations") { ptrdiff_t a[3] = {0, 1, 2}; ptrdiff_t b[3] = {3, 4, 5}; @@ -1465,7 +1465,7 @@ void iterate_second_column(multi_span av) } } -TEST(span_section_iteration) +TEST_CASE("span_section_iteration") { int arr[4][2] = {{4, 0}, {5, 1}, {6, 2}, {7, 3}}; @@ -1491,7 +1491,7 @@ TEST(span_section_iteration) } } -TEST(dynamic_span_section_iteration) +TEST_CASE("dynamic_span_section_iteration") { auto height = 4, width = 2; auto size = height * width; @@ -1523,7 +1523,7 @@ TEST(dynamic_span_section_iteration) delete[] arr; } -TEST(span_structure_size) +TEST_CASE("span_structure_size") { double(*arr)[3][4] = new double[100][3][4]; multi_span av1(arr, 10); @@ -1535,14 +1535,14 @@ TEST(span_structure_size) }; CHECK(sizeof(av1) == sizeof(EffectiveStructure)); - CHECK_THROW(av1[10][3][4], fail_fast); + CHECK_THROWS_AS(av1[10][3][4], fail_fast); multi_span av2 = as_multi_span(av1, dim(5), dim<6>(), dim<4>()); (void) av2; } -TEST(fixed_size_conversions) +TEST_CASE("fixed_size_conversions") { int arr[] = {1, 2, 3, 4}; @@ -1626,7 +1626,7 @@ TEST(fixed_size_conversions) multi_span av9 = {arr2, 2}; (void) av9; }; - CHECK_THROW(f(), fail_fast); + CHECK_THROWS_AS(f(), fail_fast); } // this should fail - we are trying to assign a small dynamic a_v to a fixed_size larger one @@ -1635,10 +1635,10 @@ TEST(fixed_size_conversions) multi_span av2 = av; (void) av2; }; - CHECK_THROW(f(), fail_fast); + CHECK_THROWS_AS(f(), fail_fast); } -TEST(as_writeable_bytes) +TEST_CASE("as_writeable_bytes") { int a[] = {1, 2, 3, 4}; @@ -1666,7 +1666,7 @@ TEST(as_writeable_bytes) } } -TEST(iterator) +TEST_CASE("iterator") { int a[] = {1, 2, 3, 4}; @@ -1691,6 +1691,3 @@ TEST(iterator) } } } -} - -int main(int, const char* []) { return UnitTest::RunAllTests(); } diff --git a/tests/notnull_tests.cpp b/tests/notnull_tests.cpp index bb043bb..86dd69a 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -14,7 +14,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include @@ -95,161 +95,155 @@ std::string operator>=(CustomPtr const& lhs, CustomPtr const& rhs) : "false"; } -SUITE(NotNullTests) +bool helper(not_null p) { return *p == 12; } + +TEST_CASE("TestNotNullConstructors") { - - bool helper(not_null p) { return *p == 12; } - - TEST(TestNotNullConstructors) - { #ifdef CONFIRM_COMPILATION_ERRORS - not_null p = nullptr; // yay...does not compile! - not_null*> p = 0; // yay...does not compile! - not_null p; // yay...does not compile! - std::unique_ptr up = std::make_unique(120); - not_null p = up; + not_null p = nullptr; // yay...does not compile! + not_null*> p = 0; // yay...does not compile! + not_null p; // yay...does not compile! + std::unique_ptr up = std::make_unique(120); + not_null p = up; - // Forbid non-nullptr assignable types - not_null> f(std::vector{1}); - not_null z(10); - not_null> y({1, 2}); + // Forbid non-nullptr assignable types + not_null> f(std::vector{1}); + not_null z(10); + not_null> y({1, 2}); #endif - int i = 12; - auto rp = RefCounted(&i); - not_null p(rp); - CHECK(p.get() == &i); + int i = 12; + auto rp = RefCounted(&i); + not_null p(rp); + CHECK(p.get() == &i); - not_null> x( - std::make_shared(10)); // shared_ptr is nullptr assignable - } - - TEST(TestNotNullCasting) - { - MyBase base; - MyDerived derived; - Unrelated unrelated; - not_null u = &unrelated; - (void) u; - not_null p = &derived; - not_null q = &base; - q = p; // allowed with heterogeneous copy ctor - CHECK(q == p); - -#ifdef CONFIRM_COMPILATION_ERRORS - q = u; // no viable conversion possible between MyBase* and Unrelated* - p = q; // not possible to implicitly convert MyBase* to MyDerived* - - not_null r = p; - not_null s = reinterpret_cast(p); -#endif - not_null t = reinterpret_cast(p.get()); - CHECK(reinterpret_cast(p.get()) == reinterpret_cast(t.get())); - } - - TEST(TestNotNullAssignment) - { - int i = 12; - not_null p = &i; - CHECK(helper(p)); - - int* q = nullptr; - CHECK_THROW(p = q, fail_fast); - } - - TEST(TestNotNullRawPointerComparison) - { - int ints[2] = {42, 43}; - int* p1 = &ints[0]; - const int* p2 = &ints[1]; - - using NotNull1 = not_null; - using NotNull2 = not_null; - - CHECK((NotNull1(p1) == NotNull1(p1)) == true); - CHECK((NotNull1(p1) == NotNull2(p2)) == false); - - CHECK((NotNull1(p1) != NotNull1(p1)) == false); - CHECK((NotNull1(p1) != NotNull2(p2)) == true); - - CHECK((NotNull1(p1) < NotNull1(p1)) == false); - CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); - CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); - - CHECK((NotNull1(p1) > NotNull1(p1)) == false); - CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); - CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); - - CHECK((NotNull1(p1) <= NotNull1(p1)) == true); - CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); - CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); - - CHECK((NotNull1(p1) >= NotNull1(p1)) == true); - CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2)); - CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); - } - - TEST(TestNotNullSharedPtrComparison) - { - auto sp1 = std::make_shared(42); - auto sp2 = std::make_shared(43); - - using NotNullSp1 = not_null; - using NotNullSp2 = not_null; - - CHECK((NotNullSp1(sp1) == NotNullSp1(sp1)) == true); - CHECK((NotNullSp1(sp1) == NotNullSp2(sp2)) == false); - - CHECK((NotNullSp1(sp1) != NotNullSp1(sp1)) == false); - CHECK((NotNullSp1(sp1) != NotNullSp2(sp2)) == true); - - CHECK((NotNullSp1(sp1) < NotNullSp1(sp1)) == false); - CHECK((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2)); - CHECK((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1)); - - CHECK((NotNullSp1(sp1) > NotNullSp1(sp1)) == false); - CHECK((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2)); - CHECK((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1)); - - CHECK((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true); - CHECK((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2)); - CHECK((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1)); - - CHECK((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true); - CHECK((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2)); - CHECK((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1)); - } - - TEST(TestNotNullCustomPtrComparison) - { - int ints[2] = {42, 43}; - CustomPtr p1(&ints[0]); - CustomPtr p2(&ints[1]); - - using NotNull1 = not_null; - using NotNull2 = not_null; - - CHECK((NotNull1(p1) == NotNull1(p1)) == "true"); - CHECK((NotNull1(p1) == NotNull2(p2)) == "false"); - - CHECK((NotNull1(p1) != NotNull1(p1)) == "false"); - CHECK((NotNull1(p1) != NotNull2(p2)) == "true"); - - CHECK((NotNull1(p1) < NotNull1(p1)) == "false"); - CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); - CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); - - CHECK((NotNull1(p1) > NotNull1(p1)) == "false"); - CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); - CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); - - CHECK((NotNull1(p1) <= NotNull1(p1)) == "true"); - CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); - CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); - - CHECK((NotNull1(p1) >= NotNull1(p1)) == "true"); - CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2)); - CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); - } + not_null> x( + std::make_shared(10)); // shared_ptr is nullptr assignable } -int main(int, const char* []) { return UnitTest::RunAllTests(); } +TEST_CASE("TestNotNullCasting") +{ + MyBase base; + MyDerived derived; + Unrelated unrelated; + not_null u = &unrelated; + (void) u; + not_null p = &derived; + not_null q = &base; + q = p; // allowed with heterogeneous copy ctor + CHECK(q == p); + +#ifdef CONFIRM_COMPILATION_ERRORS + q = u; // no viable conversion possible between MyBase* and Unrelated* + p = q; // not possible to implicitly convert MyBase* to MyDerived* + + not_null r = p; + not_null s = reinterpret_cast(p); +#endif + not_null t = reinterpret_cast(p.get()); + CHECK(reinterpret_cast(p.get()) == reinterpret_cast(t.get())); +} + +TEST_CASE("TestNotNullAssignment") +{ + int i = 12; + not_null p = &i; + CHECK(helper(p)); + + int* q = nullptr; + CHECK_THROWS_AS(p = q, fail_fast); +} + +TEST_CASE("TestNotNullRawPointerComparison") +{ + int ints[2] = {42, 43}; + int* p1 = &ints[0]; + const int* p2 = &ints[1]; + + using NotNull1 = not_null; + using NotNull2 = not_null; + + CHECK((NotNull1(p1) == NotNull1(p1)) == true); + CHECK((NotNull1(p1) == NotNull2(p2)) == false); + + CHECK((NotNull1(p1) != NotNull1(p1)) == false); + CHECK((NotNull1(p1) != NotNull2(p2)) == true); + + CHECK((NotNull1(p1) < NotNull1(p1)) == false); + CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); + CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); + + CHECK((NotNull1(p1) > NotNull1(p1)) == false); + CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); + CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); + + CHECK((NotNull1(p1) <= NotNull1(p1)) == true); + CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); + CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); + + CHECK((NotNull1(p1) >= NotNull1(p1)) == true); + CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2)); + CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); +} + +TEST_CASE("TestNotNullSharedPtrComparison") +{ + auto sp1 = std::make_shared(42); + auto sp2 = std::make_shared(43); + + using NotNullSp1 = not_null; + using NotNullSp2 = not_null; + + CHECK((NotNullSp1(sp1) == NotNullSp1(sp1)) == true); + CHECK((NotNullSp1(sp1) == NotNullSp2(sp2)) == false); + + CHECK((NotNullSp1(sp1) != NotNullSp1(sp1)) == false); + CHECK((NotNullSp1(sp1) != NotNullSp2(sp2)) == true); + + CHECK((NotNullSp1(sp1) < NotNullSp1(sp1)) == false); + CHECK((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2)); + CHECK((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1)); + + CHECK((NotNullSp1(sp1) > NotNullSp1(sp1)) == false); + CHECK((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2)); + CHECK((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1)); + + CHECK((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true); + CHECK((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2)); + CHECK((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1)); + + CHECK((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true); + CHECK((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2)); + CHECK((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1)); +} + +TEST_CASE("TestNotNullCustomPtrComparison") +{ + int ints[2] = {42, 43}; + CustomPtr p1(&ints[0]); + CustomPtr p2(&ints[1]); + + using NotNull1 = not_null; + using NotNull2 = not_null; + + CHECK((NotNull1(p1) == NotNull1(p1)) == "true"); + CHECK((NotNull1(p1) == NotNull2(p2)) == "false"); + + CHECK((NotNull1(p1) != NotNull1(p1)) == "false"); + CHECK((NotNull1(p1) != NotNull2(p2)) == "true"); + + CHECK((NotNull1(p1) < NotNull1(p1)) == "false"); + CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); + CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); + + CHECK((NotNull1(p1) > NotNull1(p1)) == "false"); + CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); + CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); + + CHECK((NotNull1(p1) <= NotNull1(p1)) == "true"); + CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); + CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); + + CHECK((NotNull1(p1) >= NotNull1(p1)) == "true"); + CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2)); + CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); +} diff --git a/tests/owner_tests.cpp b/tests/owner_tests.cpp index b719b13..9335302 100644 --- a/tests/owner_tests.cpp +++ b/tests/owner_tests.cpp @@ -14,7 +14,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include @@ -22,18 +22,13 @@ using namespace gsl; -SUITE(owner_tests) +void f(int* i) { *i += 1; } + +TEST_CASE("basic_test") { - void f(int* i) { *i += 1; } - - TEST(basic_test) - { - owner p = new int(120); - CHECK(*p == 120); - f(p); - CHECK(*p == 121); - delete p; - } + owner p = new int(120); + CHECK(*p == 120); + f(p); + CHECK(*p == 121); + delete p; } - -int main(int, const char* []) { return UnitTest::RunAllTests(); } diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 6af41c6..69a7923 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -14,7 +14,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include @@ -39,748 +39,749 @@ struct DerivedClass : BaseClass }; } -SUITE(span_tests) +TEST_CASE("default_constructor") { - TEST(default_constructor) { - { - span s; - CHECK(s.length() == 0 && s.data() == nullptr); + span s; + CHECK((s.length() == 0 && s.data() == nullptr)); - span cs; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } + span cs; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } - { - span s; - CHECK(s.length() == 0 && s.data() == nullptr); + { + span s; + CHECK((s.length() == 0 && s.data() == nullptr)); - span cs; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } + span cs; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } - { + { #ifdef CONFIRM_COMPILATION_ERRORS - span s; - CHECK(s.length() == 1 && s.data() == nullptr); // explains why it can't compile + span s; + CHECK((s.length() == 1 && s.data() == nullptr)); // explains why it can't compile #endif - } - - { - span s{}; - CHECK(s.length() == 0 && s.data() == nullptr); - - span cs{}; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } } - TEST(size_optimization) { - { - span s; - CHECK(sizeof(s) == sizeof(int*) + sizeof(ptrdiff_t)); - } + span s{}; + CHECK((s.length() == 0 && s.data() == nullptr)); - { - span s; - CHECK(sizeof(s) == sizeof(int*)); - } + span cs{}; + CHECK((cs.length() == 0 && cs.data() == nullptr)); } - - TEST(from_nullptr_constructor) - { - { - span s = nullptr; - CHECK(s.length() == 0 && s.data() == nullptr); - - span cs = nullptr; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - - { - span s = nullptr; - CHECK(s.length() == 0 && s.data() == nullptr); - - span cs = nullptr; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - span s = nullptr; - CHECK(s.length() == 1 && s.data() == nullptr); // explains why it can't compile -#endif - } - - { - span s{nullptr}; - CHECK(s.length() == 0 && s.data() == nullptr); - - span cs{nullptr}; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - - { - span s{nullptr}; - CHECK(s.length() == 0 && s.data() == nullptr); - - span cs{nullptr}; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - } - - TEST(from_nullptr_length_constructor) - { - { - span s{nullptr, static_cast::index_type>(0)}; - CHECK(s.length() == 0 && s.data() == nullptr); - - span cs{nullptr, static_cast::index_type>(0)}; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - - { - span s{nullptr, static_cast::index_type>(0)}; - CHECK(s.length() == 0 && s.data() == nullptr); - - span cs{nullptr, static_cast::index_type>(0)}; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - - { - auto workaround_macro = []() { - span s{nullptr, static_cast::index_type>(0)}; - }; - CHECK_THROW(workaround_macro(), fail_fast); - } - - { - auto workaround_macro = []() { span s{nullptr, 1}; }; - CHECK_THROW(workaround_macro(), fail_fast); - - auto const_workaround_macro = []() { span cs{nullptr, 1}; }; - CHECK_THROW(const_workaround_macro(), fail_fast); - } - - { - auto workaround_macro = []() { span s{nullptr, 1}; }; - CHECK_THROW(workaround_macro(), fail_fast); - - auto const_workaround_macro = []() { span s{nullptr, 1}; }; - CHECK_THROW(const_workaround_macro(), fail_fast); - } - - { - span s{nullptr, static_cast::index_type>(0)}; - CHECK(s.length() == 0 && s.data() == nullptr); - - span cs{nullptr, static_cast::index_type>(0)}; - CHECK(cs.length() == 0 && cs.data() == nullptr); - } - } - - TEST(from_pointer_length_constructor) - { - int arr[4] = {1, 2, 3, 4}; - - { - span s{&arr[0], 2}; - CHECK(s.length() == 2 && s.data() == &arr[0]); - CHECK(s[0] == 1 && s[1] == 2); - } - - { - span s{&arr[0], 2}; - CHECK(s.length() == 2 && s.data() == &arr[0]); - CHECK(s[0] == 1 && s[1] == 2); - } - - { - int* p = nullptr; - span s{p, static_cast::index_type>(0)}; - CHECK(s.length() == 0 && s.data() == nullptr); - } - - { - int* p = nullptr; - auto workaround_macro = [=]() { span s{p, 2}; }; - CHECK_THROW(workaround_macro(), fail_fast); - } - - { - auto s = make_span(&arr[0], 2); - CHECK(s.length() == 2 && s.data() == &arr[0]); - CHECK(s[0] == 1 && s[1] == 2); - } - - { - int* p = nullptr; - auto s = make_span(p, static_cast::index_type>(0)); - CHECK(s.length() == 0 && s.data() == nullptr); - } - - { - int* p = nullptr; - auto workaround_macro = [=]() { make_span(p, 2); }; - CHECK_THROW(workaround_macro(), fail_fast); - } - } - - TEST(from_pointer_pointer_constructor) - { - int arr[4] = {1, 2, 3, 4}; - - { - span s{&arr[0], &arr[2]}; - CHECK(s.length() == 2 && s.data() == &arr[0]); - CHECK(s[0] == 1 && s[1] == 2); - } - - { - span s{&arr[0], &arr[2]}; - CHECK(s.length() == 2 && s.data() == &arr[0]); - CHECK(s[0] == 1 && s[1] == 2); - } - - { - span s{&arr[0], &arr[0]}; - CHECK(s.length() == 0 && s.data() == &arr[0]); - } - - { - span s{&arr[0], &arr[0]}; - CHECK(s.length() == 0 && s.data() == &arr[0]); - } - - // this will fail the std::distance() precondition, which asserts on MSVC debug builds - //{ - // auto workaround_macro = [&]() { span s{&arr[1], &arr[0]}; }; - // CHECK_THROW(workaround_macro(), fail_fast); - //} - - // this will fail the std::distance() precondition, which asserts on MSVC debug builds - //{ - // int* p = nullptr; - // auto workaround_macro = [&]() { span s{&arr[0], p}; }; - // CHECK_THROW(workaround_macro(), fail_fast); - //} - - { - int* p = nullptr; - span s{p, p}; - CHECK(s.length() == 0 && s.data() == nullptr); - } - - { - int* p = nullptr; - span s{p, p}; - CHECK(s.length() == 0 && s.data() == nullptr); - } - - // this will fail the std::distance() precondition, which asserts on MSVC debug builds - //{ - // int* p = nullptr; - // auto workaround_macro = [&]() { span s{&arr[0], p}; }; - // CHECK_THROW(workaround_macro(), fail_fast); - //} - - { - auto s = make_span(&arr[0], &arr[2]); - CHECK(s.length() == 2 && s.data() == &arr[0]); - CHECK(s[0] == 1 && s[1] == 2); - } - - { - auto s = make_span(&arr[0], &arr[0]); - CHECK(s.length() == 0 && s.data() == &arr[0]); - } - - { - int* p = nullptr; - auto s = make_span(p, p); - CHECK(s.length() == 0 && s.data() == nullptr); - } - } - - TEST(from_array_constructor) - { - int arr[5] = {1, 2, 3, 4, 5}; - - { - span s{arr}; - CHECK(s.length() == 5 && s.data() == &arr[0]); - } - - { - span s{arr}; - CHECK(s.length() == 5 && s.data() == &arr[0]); - } - - int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; - -#ifdef CONFIRM_COMPILATION_ERRORS - { - span s{arr}; - } - - { - span s{arr}; - CHECK(s.length() == 0 && s.data() == &arr[0]); - } - - { - span s{arr2d}; - CHECK(s.length() == 6 && s.data() == &arr2d[0][0]); - CHECK(s[0] == 1 && s[5] == 6); - } - - { - span s{arr2d}; - CHECK(s.length() == 0 && s.data() == &arr2d[0][0]); - } - - { - span s{arr2d}; - } -#endif - { - span s{&(arr2d[0]), 1}; - CHECK(s.length() == 1 && s.data() == &arr2d[0]); - } - - int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - -#ifdef CONFIRM_COMPILATION_ERRORS - { - span s{arr3d}; - CHECK(s.length() == 12 && s.data() == &arr3d[0][0][0]); - CHECK(s[0] == 1 && s[11] == 12); - } - - { - span s{arr3d}; - CHECK(s.length() == 0 && s.data() == &arr3d[0][0][0]); - } - - { - span s{arr3d}; - } - - { - span s{arr3d}; - CHECK(s.length() == 12 && s.data() == &arr3d[0][0][0]); - CHECK(s[0] == 1 && s[5] == 6); - } -#endif - { - span s{&arr3d[0], 1}; - CHECK(s.length() == 1 && s.data() == &arr3d[0]); - } - - { - auto s = make_span(arr); - CHECK(s.length() == 5 && s.data() == &arr[0]); - } - - { - auto s = make_span(&(arr2d[0]), 1); - CHECK(s.length() == 1 && s.data() == &arr2d[0]); - } - - { - auto s = make_span(&arr3d[0], 1); - CHECK(s.length() == 1 && s.data() == &arr3d[0]); - } - } - - TEST(from_dynamic_array_constructor) - { - double(*arr)[3][4] = new double[100][3][4]; - - { - span s(&arr[0][0][0], 10); - CHECK(s.length() == 10 && s.data() == &arr[0][0][0]); - } - - { - auto s = make_span(&arr[0][0][0], 10); - CHECK(s.length() == 10 && s.data() == &arr[0][0][0]); - } - - delete[] arr; - } - - TEST(from_std_array_constructor) - { - std::array arr = {1, 2, 3, 4}; - - { - span s{arr}; - CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - - span cs{arr}; - CHECK(cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data()); - } - - { - span s{arr}; - CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - - span cs{arr}; - CHECK(cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data()); - } - -#ifdef CONFIRM_COMPILATION_ERRORS - { - span s{arr}; - CHECK(s.size() == 2 && s.data() == arr.data()); - - span cs{arr}; - CHECK(cs.size() == 2 && cs.data() == arr.data()); - } - - { - span s{arr}; - CHECK(s.size() == 0 && s.data() == arr.data()); - - span cs{arr}; - CHECK(cs.size() == 0 && cs.data() == arr.data()); - } - - { - span s{arr}; - } - - { - auto get_an_array = []() -> std::array { return {1, 2, 3, 4}; }; - auto take_a_span = [](span s) { static_cast(s); }; - // try to take a temporary std::array - take_a_span(get_an_array()); - } -#endif - - { - auto get_an_array = []() -> std::array { return {1, 2, 3, 4}; }; - auto take_a_span = [](span s) { static_cast(s); }; - // try to take a temporary std::array - take_a_span(get_an_array()); - } - - { - auto s = make_span(arr); - CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - } - } - - TEST(from_const_std_array_constructor) - { - const std::array arr = {1, 2, 3, 4}; - - { - span s{arr}; - CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - } - - { - span s{arr}; - CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - } - -#ifdef CONFIRM_COMPILATION_ERRORS - { - span s{arr}; - CHECK(s.size() == 2 && s.data() == arr.data()); - } - - { - span s{arr}; - CHECK(s.size() == 0 && s.data() == arr.data()); - } - - { - span s{arr}; - } -#endif - - { - auto get_an_array = []() -> const std::array { return {1, 2, 3, 4}; }; - auto take_a_span = [](span s) { static_cast(s); }; - // try to take a temporary std::array - take_a_span(get_an_array()); - } - - { - auto s = make_span(arr); - CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - } - } - - TEST(from_std_array_const_constructor) - { - std::array arr = {1, 2, 3, 4}; - - { - span s{arr}; - CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - } - - { - span s{arr}; - CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - } - -#ifdef CONFIRM_COMPILATION_ERRORS - { - span s{arr}; - CHECK(s.size() == 2 && s.data() == arr.data()); - } - - { - span s{arr}; - CHECK(s.size() == 0 && s.data() == arr.data()); - } - - { - span s{arr}; - } - - { - span s{arr}; - } -#endif - - { - auto s = make_span(arr); - CHECK(s.size() == narrow_cast(arr.size()) && s.data() == arr.data()); - } - } - - TEST(from_unique_pointer_construction) - { - { - auto ptr = std::make_unique(4); - - { - span s{ptr}; - CHECK(s.length() == 1 && s.data() == ptr.get()); - CHECK(s[0] == 4); - } - - { - auto s = make_span(ptr); - CHECK(s.length() == 1 && s.data() == ptr.get()); - CHECK(s[0] == 4); - } - } - - { - auto ptr = std::unique_ptr{nullptr}; - - { - span s{ptr}; - CHECK(s.length() == 0 && s.data() == nullptr); - } - - { - auto s = make_span(ptr); - CHECK(s.length() == 0 && s.data() == nullptr); - } - } - - { - auto arr = std::make_unique(4); - - for (auto i = 0U; i < 4; i++) arr[i] = gsl::narrow_cast(i + 1); - - { - span s{arr, 4}; - CHECK(s.length() == 4 && s.data() == arr.get()); - CHECK(s[0] == 1 && s[1] == 2); - } - - { - auto s = make_span(arr, 4); - CHECK(s.length() == 4 && s.data() == arr.get()); - CHECK(s[0] == 1 && s[1] == 2); - } - } - - { - auto arr = std::unique_ptr{nullptr}; - - { - span s{arr, 0}; - CHECK(s.length() == 0 && s.data() == nullptr); - } - - { - auto s = make_span(arr, 0); - CHECK(s.length() == 0 && s.data() == nullptr); - } - } - } - - TEST(from_shared_pointer_construction) - { - { - auto ptr = std::make_shared(4); - - { - span s{ptr}; - CHECK(s.length() == 1 && s.data() == ptr.get()); - CHECK(s[0] == 4); - } - - { - auto s = make_span(ptr); - CHECK(s.length() == 1 && s.data() == ptr.get()); - CHECK(s[0] == 4); - } - } - - { - auto ptr = std::shared_ptr{nullptr}; - - { - span s{ptr}; - CHECK(s.length() == 0 && s.data() == nullptr); - } - - { - auto s = make_span(ptr); - CHECK(s.length() == 0 && s.data() == nullptr); - } - } - } - - TEST(from_container_constructor) - { - std::vector v = {1, 2, 3}; - const std::vector cv = v; - - { - span s{v}; - CHECK(s.size() == narrow_cast(v.size()) && s.data() == v.data()); - - span cs{v}; - CHECK(cs.size() == narrow_cast(v.size()) && cs.data() == v.data()); - } - - std::string str = "hello"; - const std::string cstr = "hello"; - - { -#ifdef CONFIRM_COMPILATION_ERRORS - span s{str}; - CHECK(s.size() == narrow_cast(str.size()) && s.data() == str.data()); -#endif - span cs{str}; - CHECK(cs.size() == narrow_cast(str.size()) && cs.data() == str.data()); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - span s{cstr}; -#endif - span cs{cstr}; - CHECK(cs.size() == narrow_cast(cstr.size()) && - cs.data() == cstr.data()); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - auto get_temp_vector = []() -> std::vector { return {}; }; - auto use_span = [](span s) { static_cast(s); }; - use_span(get_temp_vector()); -#endif - } - - { - auto get_temp_vector = []() -> std::vector { return {}; }; - auto use_span = [](span s) { static_cast(s); }; - use_span(get_temp_vector()); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - auto get_temp_string = []() -> std::string { return {}; }; - auto use_span = [](span s) { static_cast(s); }; - use_span(get_temp_string()); -#endif - } - - { - auto get_temp_string = []() -> std::string { return {}; }; - auto use_span = [](span s) { static_cast(s); }; - use_span(get_temp_string()); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - auto get_temp_vector = []() -> const std::vector { return {}; }; - auto use_span = [](span s) { static_cast(s); }; - use_span(get_temp_vector()); -#endif - } - - { - auto get_temp_string = []() -> const std::string { return {}; }; - auto use_span = [](span s) { static_cast(s); }; - use_span(get_temp_string()); - } - - { -#ifdef CONFIRM_COMPILATION_ERRORS - std::map m; - span s{m}; -#endif - } - - { - auto s = make_span(v); - CHECK(s.size() == narrow_cast(v.size()) && s.data() == v.data()); - - auto cs = make_span(cv); - CHECK(cs.size() == narrow_cast(cv.size()) && cs.data() == cv.data()); - } - } - - TEST(from_convertible_span_constructor){{span avd; - span avcd = avd; - static_cast(avcd); } +TEST_CASE("size_optimization") { -#ifdef CONFIRM_COMPILATION_ERRORS - span avd; - span avb = avd; - static_cast(avb); -#endif + { + span s; + CHECK(sizeof(s) == sizeof(int*) + sizeof(ptrdiff_t)); + } + + { + span s; + CHECK(sizeof(s) == sizeof(int*)); + } } +TEST_CASE("from_nullptr_constructor") +{ + { + span s = nullptr; + CHECK((s.length() == 0 && s.data() == nullptr)); + + span cs = nullptr; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } + + { + span s = nullptr; + CHECK((s.length() == 0 && s.data() == nullptr)); + + span cs = nullptr; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + span s = nullptr; + CHECK((s.length() == 1 && s.data() == nullptr)); // explains why it can't compile +#endif + } + + { + span s{nullptr}; + CHECK((s.length() == 0 && s.data() == nullptr)); + + span cs{nullptr}; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } + + { + span s{nullptr}; + CHECK((s.length() == 0 && s.data() == nullptr)); + + span cs{nullptr}; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } +} + +TEST_CASE("from_nullptr_length_constructor") +{ + { + span s{nullptr, static_cast::index_type>(0)}; + CHECK((s.length() == 0 && s.data() == nullptr)); + + span cs{nullptr, static_cast::index_type>(0)}; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } + + { + span s{nullptr, static_cast::index_type>(0)}; + CHECK((s.length() == 0 && s.data() == nullptr)); + + span cs{nullptr, static_cast::index_type>(0)}; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } + + { + auto workaround_macro = []() { + span s{nullptr, static_cast::index_type>(0)}; + }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } + + { + auto workaround_macro = []() { span s{nullptr, 1}; }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + + auto const_workaround_macro = []() { span cs{nullptr, 1}; }; + CHECK_THROWS_AS(const_workaround_macro(), fail_fast); + } + + { + auto workaround_macro = []() { span s{nullptr, 1}; }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + + auto const_workaround_macro = []() { span s{nullptr, 1}; }; + CHECK_THROWS_AS(const_workaround_macro(), fail_fast); + } + + { + span s{nullptr, static_cast::index_type>(0)}; + CHECK((s.length() == 0 && s.data() == nullptr)); + + span cs{nullptr, static_cast::index_type>(0)}; + CHECK((cs.length() == 0 && cs.data() == nullptr)); + } +} + +TEST_CASE("from_pointer_length_constructor") +{ + int arr[4] = {1, 2, 3, 4}; + + { + span s{&arr[0], 2}; + CHECK((s.length() == 2 && s.data() == &arr[0])); + CHECK((s[0] == 1 && s[1] == 2)); + } + + { + span s{&arr[0], 2}; + CHECK((s.length() == 2 && s.data() == &arr[0])); + CHECK((s[0] == 1 && s[1] == 2)); + } + + { + int* p = nullptr; + span s{p, static_cast::index_type>(0)}; + CHECK((s.length() == 0 && s.data() == nullptr)); + } + + { + int* p = nullptr; + auto workaround_macro = [=]() { span s{p, 2}; }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } + + { + auto s = make_span(&arr[0], 2); + CHECK((s.length() == 2 && s.data() == &arr[0])); + CHECK((s[0] == 1 && s[1] == 2)); + } + + { + int* p = nullptr; + auto s = make_span(p, static_cast::index_type>(0)); + CHECK((s.length() == 0 && s.data() == nullptr)); + } + + { + int* p = nullptr; + auto workaround_macro = [=]() { make_span(p, 2); }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } +} + +TEST_CASE("from_pointer_pointer_constructor") +{ + int arr[4] = {1, 2, 3, 4}; + + { + span s{&arr[0], &arr[2]}; + CHECK((s.length() == 2 && s.data() == &arr[0])); + CHECK((s[0] == 1 && s[1] == 2)); + } + + { + span s{&arr[0], &arr[2]}; + CHECK((s.length() == 2 && s.data() == &arr[0])); + CHECK((s[0] == 1 && s[1] == 2)); + } + + { + span s{&arr[0], &arr[0]}; + CHECK((s.length() == 0 && s.data() == &arr[0])); + } + + { + span s{&arr[0], &arr[0]}; + CHECK((s.length() == 0 && s.data() == &arr[0])); + } + + // this will fail the std::distance() precondition, which asserts on MSVC debug builds + //{ + // auto workaround_macro = [&]() { span s{&arr[1], &arr[0]}; }; + // CHECK_THROWS_AS(workaround_macro(), fail_fast); + //} + + // this will fail the std::distance() precondition, which asserts on MSVC debug builds + //{ + // int* p = nullptr; + // auto workaround_macro = [&]() { span s{&arr[0], p}; }; + // CHECK_THROWS_AS(workaround_macro(), fail_fast); + //} + + { + int* p = nullptr; + span s{p, p}; + CHECK((s.length() == 0 && s.data() == nullptr)); + } + + { + int* p = nullptr; + span s{p, p}; + CHECK((s.length() == 0 && s.data() == nullptr)); + } + + // this will fail the std::distance() precondition, which asserts on MSVC debug builds + //{ + // int* p = nullptr; + // auto workaround_macro = [&]() { span s{&arr[0], p}; }; + // CHECK_THROWS_AS(workaround_macro(), fail_fast); + //} + + { + auto s = make_span(&arr[0], &arr[2]); + CHECK((s.length() == 2 && s.data() == &arr[0])); + CHECK((s[0] == 1 && s[1] == 2)); + } + + { + auto s = make_span(&arr[0], &arr[0]); + CHECK((s.length() == 0 && s.data() == &arr[0])); + } + + { + int* p = nullptr; + auto s = make_span(p, p); + CHECK((s.length() == 0 && s.data() == nullptr)); + } +} + +TEST_CASE("from_array_constructor") +{ + int arr[5] = {1, 2, 3, 4, 5}; + + { + span s{arr}; + CHECK((s.length() == 5 && s.data() == &arr[0])); + } + + { + span s{arr}; + CHECK((s.length() == 5 && s.data() == &arr[0])); + } + + int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; + #ifdef CONFIRM_COMPILATION_ERRORS -{ - span s; - span s2 = s; - static_cast(s2); -} + { + span s{arr}; + } -{ - span s; - span s2 = s; - static_cast(s2); -} + { + span s{arr}; + CHECK((s.length() == 0 && s.data() == &arr[0])); + } -{ - span s; - span s2 = s; - static_cast(s2); -} + { + span s{arr2d}; + CHECK((s.length() == 6 && s.data() == &arr2d[0][0])); + CHECK((s[0] == 1 && s[5] == 6)); + } + + { + span s{arr2d}; + CHECK((s.length() == 0 && s.data() == &arr2d[0][0])); + } + + { + span s{arr2d}; + } #endif + { + span s{&(arr2d[0]), 1}; + CHECK((s.length() == 1 && s.data() == &arr2d[0])); + } + + int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + +#ifdef CONFIRM_COMPILATION_ERRORS + { + span s{arr3d}; + CHECK((s.length() == 12 && s.data() == &arr3d[0][0][0])); + CHECK((s[0] == 1 && s[11] == 12)); + } + + { + span s{arr3d}; + CHECK((s.length() == 0 && s.data() == &arr3d[0][0][0])); + } + + { + span s{arr3d}; + } + + { + span s{arr3d}; + CHECK((s.length() == 12 && s.data() == &arr3d[0][0][0])); + CHECK((s[0] == 1 && s[5] == 6)); + } +#endif + { + span s{&arr3d[0], 1}; + CHECK((s.length() == 1 && s.data() == &arr3d[0])); + } + + { + auto s = make_span(arr); + CHECK((s.length() == 5 && s.data() == &arr[0])); + } + + { + auto s = make_span(&(arr2d[0]), 1); + CHECK((s.length() == 1 && s.data() == &arr2d[0])); + } + + { + auto s = make_span(&arr3d[0], 1); + CHECK((s.length() == 1 && s.data() == &arr3d[0])); + } } -TEST(copy_move_and_assignment) +TEST_CASE("from_dynamic_array_constructor") +{ + double(*arr)[3][4] = new double[100][3][4]; + + { + span s(&arr[0][0][0], 10); + CHECK((s.length() == 10 && s.data() == &arr[0][0][0])); + } + + { + auto s = make_span(&arr[0][0][0], 10); + CHECK((s.length() == 10 && s.data() == &arr[0][0][0])); + } + + delete[] arr; +} + +TEST_CASE("from_std_array_constructor") +{ + std::array arr = {1, 2, 3, 4}; + + { + span s{arr}; + CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); + + span cs{arr}; + CHECK((cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data())); + } + + { + span s{arr}; + CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); + + span cs{arr}; + CHECK((cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data())); + } + +#ifdef CONFIRM_COMPILATION_ERRORS + { + span s{arr}; + CHECK((s.size() == 2 && s.data() == arr.data())); + + span cs{arr}; + CHECK((cs.size() == 2 && cs.data() == arr.data())); + } + + { + span s{arr}; + CHECK((s.size() == 0 && s.data() == arr.data())); + + span cs{arr}; + CHECK((cs.size() == 0 && cs.data() == arr.data())); + } + + { + span s{arr}; + } + + { + auto get_an_array = []() -> std::array { return {1, 2, 3, 4}; }; + auto take_a_span = [](span s) { static_cast(s); }; + // try to take a temporary std::array + take_a_span(get_an_array()); + } +#endif + + { + auto get_an_array = []() -> std::array { return {1, 2, 3, 4}; }; + auto take_a_span = [](span s) { static_cast(s); }; + // try to take a temporary std::array + take_a_span(get_an_array()); + } + + { + auto s = make_span(arr); + CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); + } +} + +TEST_CASE("from_const_std_array_constructor") +{ + const std::array arr = {1, 2, 3, 4}; + + { + span s{arr}; + CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); + } + + { + span s{arr}; + CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); + } + +#ifdef CONFIRM_COMPILATION_ERRORS + { + span s{arr}; + CHECK((s.size() == 2 && s.data() == arr.data())); + } + + { + span s{arr}; + CHECK((s.size() == 0 && s.data() == arr.data())); + } + + { + span s{arr}; + } +#endif + + { + auto get_an_array = []() -> const std::array { return {1, 2, 3, 4}; }; + auto take_a_span = [](span s) { static_cast(s); }; + // try to take a temporary std::array + take_a_span(get_an_array()); + } + + { + auto s = make_span(arr); + CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); + } +} + +TEST_CASE("from_std_array_const_constructor") +{ + std::array arr = {1, 2, 3, 4}; + + { + span s{arr}; + CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); + } + + { + span s{arr}; + CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); + } + +#ifdef CONFIRM_COMPILATION_ERRORS + { + span s{arr}; + CHECK((s.size() == 2 && s.data() == arr.data())); + } + + { + span s{arr}; + CHECK((s.size() == 0 && s.data() == arr.data())); + } + + { + span s{arr}; + } + + { + span s{arr}; + } +#endif + + { + auto s = make_span(arr); + CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); + } +} + +TEST_CASE("from_unique_pointer_construction") +{ + { + auto ptr = std::make_unique(4); + + { + span s{ptr}; + CHECK((s.length() == 1 && s.data() == ptr.get())); + CHECK(s[0] == 4); + } + + { + auto s = make_span(ptr); + CHECK((s.length() == 1 && s.data() == ptr.get())); + CHECK(s[0] == 4); + } + } + + { + auto ptr = std::unique_ptr{nullptr}; + + { + span s{ptr}; + CHECK((s.length() == 0 && s.data() == nullptr)); + } + + { + auto s = make_span(ptr); + CHECK((s.length() == 0 && s.data() == nullptr)); + } + } + + { + auto arr = std::make_unique(4); + + for (auto i = 0U; i < 4; i++) arr[i] = gsl::narrow_cast(i + 1); + + { + span s{arr, 4}; + CHECK((s.length() == 4 && s.data() == arr.get())); + CHECK((s[0] == 1 && s[1] == 2)); + } + + { + auto s = make_span(arr, 4); + CHECK((s.length() == 4 && s.data() == arr.get())); + CHECK((s[0] == 1 && s[1] == 2)); + } + } + + { + auto arr = std::unique_ptr{nullptr}; + + { + span s{arr, 0}; + CHECK((s.length() == 0 && s.data() == nullptr)); + } + + { + auto s = make_span(arr, 0); + CHECK((s.length() == 0 && s.data() == nullptr)); + } + } +} + +TEST_CASE("from_shared_pointer_construction") +{ + { + auto ptr = std::make_shared(4); + + { + span s{ptr}; + CHECK((s.length() == 1 && s.data() == ptr.get())); + CHECK((s[0] == 4)); + } + + { + auto s = make_span(ptr); + CHECK((s.length() == 1 && s.data() == ptr.get())); + CHECK((s[0] == 4)); + } + } + + { + auto ptr = std::shared_ptr{nullptr}; + + { + span s{ptr}; + CHECK((s.length() == 0 && s.data() == nullptr)); + } + + { + auto s = make_span(ptr); + CHECK((s.length() == 0 && s.data() == nullptr)); + } + } +} + +TEST_CASE("from_container_constructor") +{ + std::vector v = {1, 2, 3}; + const std::vector cv = v; + + { + span s{v}; + CHECK((s.size() == narrow_cast(v.size()) && s.data() == v.data())); + + span cs{v}; + CHECK((cs.size() == narrow_cast(v.size()) && cs.data() == v.data())); + } + + std::string str = "hello"; + const std::string cstr = "hello"; + + { +#ifdef CONFIRM_COMPILATION_ERRORS + span s{str}; + CHECK((s.size() == narrow_cast(str.size()) && s.data() == str.data())); +#endif + span cs{str}; + CHECK((cs.size() == narrow_cast(str.size()) && cs.data() == str.data())); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + span s{cstr}; +#endif + span cs{cstr}; + CHECK((cs.size() == narrow_cast(cstr.size()) && + cs.data() == cstr.data())); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_temp_vector = []() -> std::vector { return {}; }; + auto use_span = [](span s) { static_cast(s); }; + use_span(get_temp_vector()); +#endif + } + + { + auto get_temp_vector = []() -> std::vector { return {}; }; + auto use_span = [](span s) { static_cast(s); }; + use_span(get_temp_vector()); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_temp_string = []() -> std::string { return {}; }; + auto use_span = [](span s) { static_cast(s); }; + use_span(get_temp_string()); +#endif + } + + { + auto get_temp_string = []() -> std::string { return {}; }; + auto use_span = [](span s) { static_cast(s); }; + use_span(get_temp_string()); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_temp_vector = []() -> const std::vector { return {}; }; + auto use_span = [](span s) { static_cast(s); }; + use_span(get_temp_vector()); +#endif + } + + { + auto get_temp_string = []() -> const std::string { return {}; }; + auto use_span = [](span s) { static_cast(s); }; + use_span(get_temp_string()); + } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::map m; + span s{m}; +#endif + } + + { + auto s = make_span(v); + CHECK((s.size() == narrow_cast(v.size()) && s.data() == v.data())); + + auto cs = make_span(cv); + CHECK((cs.size() == narrow_cast(cv.size()) && cs.data() == cv.data())); + } +} + +TEST_CASE("from_convertible_span_constructor") +{ + { + span avd; + span avcd = avd; + static_cast(avcd); + } + + { + #ifdef CONFIRM_COMPILATION_ERRORS + span avd; + span avb = avd; + static_cast(avb); + #endif + } + + #ifdef CONFIRM_COMPILATION_ERRORS + { + span s; + span s2 = s; + static_cast(s2); + } + + { + span s; + span s2 = s; + static_cast(s2); + } + + { + span s; + span s2 = s; + static_cast(s2); + } + #endif +} + +TEST_CASE("copy_move_and_assignment") { span s1; CHECK(s1.empty()); @@ -788,20 +789,20 @@ TEST(copy_move_and_assignment) int arr[] = {3, 4, 5}; span s2 = arr; - CHECK(s2.length() == 3 && s2.data() == &arr[0]); + CHECK((s2.length() == 3 && s2.data() == &arr[0])); s2 = s1; CHECK(s2.empty()); auto get_temp_span = [&]() -> span { return {&arr[1], 2}; }; - auto use_span = [&](span s) { CHECK(s.length() == 2 && s.data() == &arr[1]); }; + auto use_span = [&](span s) { CHECK((s.length() == 2 && s.data() == &arr[1])); }; use_span(get_temp_span()); s1 = get_temp_span(); - CHECK(s1.length() == 2 && s1.data() == &arr[1]); + CHECK((s1.length() == 2 && s1.data() == &arr[1])); } -TEST(first) +TEST_CASE("first") { int arr[5] = {1, 2, 3, 4, 5}; @@ -829,7 +830,7 @@ TEST(first) CHECK(av.first<6>().length() == 6); CHECK(av.first<-1>().length() == -1); #endif - CHECK_THROW(av.first(6).length(), fail_fast); + CHECK_THROWS_AS(av.first(6).length(), fail_fast); } { @@ -839,7 +840,7 @@ TEST(first) } } -TEST(last) +TEST_CASE("last") { int arr[5] = {1, 2, 3, 4, 5}; @@ -866,7 +867,7 @@ TEST(last) #ifdef CONFIRM_COMPILATION_ERRORS CHECK(av.last<6>().length() == 6); #endif - CHECK_THROW(av.last(6).length(), fail_fast); + CHECK_THROWS_AS(av.last(6).length(), fail_fast); } { @@ -876,7 +877,7 @@ TEST(last) } } -TEST(subspan) +TEST_CASE("subspan") { int arr[5] = {1, 2, 3, 4, 5}; @@ -897,8 +898,8 @@ TEST(subspan) span av = arr; CHECK((av.subspan<0, 5>().length() == 5)); CHECK(av.subspan(0, 5).length() == 5); - CHECK_THROW(av.subspan(0, 6).length(), fail_fast); - CHECK_THROW(av.subspan(1, 5).length(), fail_fast); + CHECK_THROWS_AS(av.subspan(0, 6).length(), fail_fast); + CHECK_THROWS_AS(av.subspan(1, 5).length(), fail_fast); } { @@ -906,20 +907,20 @@ TEST(subspan) CHECK((av.subspan<4, 0>().length() == 0)); CHECK(av.subspan(4, 0).length() == 0); CHECK(av.subspan(5, 0).length() == 0); - CHECK_THROW(av.subspan(6, 0).length(), fail_fast); + CHECK_THROWS_AS(av.subspan(6, 0).length(), fail_fast); } { span av; CHECK((av.subspan<0, 0>().length() == 0)); CHECK(av.subspan(0, 0).length() == 0); - CHECK_THROW((av.subspan<1, 0>().length()), fail_fast); + CHECK_THROWS_AS((av.subspan<1, 0>().length()), fail_fast); } { span av; CHECK(av.subspan(0).length() == 0); - CHECK_THROW(av.subspan(1).length(), fail_fast); + CHECK_THROWS_AS(av.subspan(1).length(), fail_fast); } { @@ -928,7 +929,7 @@ TEST(subspan) CHECK(av.subspan(1).length() == 4); CHECK(av.subspan(4).length() == 1); CHECK(av.subspan(5).length() == 0); - CHECK_THROW(av.subspan(6).length(), fail_fast); + CHECK_THROWS_AS(av.subspan(6).length(), fail_fast); const auto av2 = av.subspan(1); for (int i = 0; i < 4; ++i) CHECK(av2[i] == i + 2); } @@ -939,20 +940,20 @@ TEST(subspan) CHECK(av.subspan(1).length() == 4); CHECK(av.subspan(4).length() == 1); CHECK(av.subspan(5).length() == 0); - CHECK_THROW(av.subspan(6).length(), fail_fast); + CHECK_THROWS_AS(av.subspan(6).length(), fail_fast); const auto av2 = av.subspan(1); for (int i = 0; i < 4; ++i) CHECK(av2[i] == i + 2); } } -TEST(at_call) +TEST_CASE("at_call") { int arr[4] = {1, 2, 3, 4}; { span s = arr; CHECK(s.at(0) == 1); - CHECK_THROW(s.at(5), fail_fast); + CHECK_THROWS_AS(s.at(5), fail_fast); } { @@ -960,18 +961,18 @@ TEST(at_call) span s = arr2d; CHECK(s.at(0) == 1); CHECK(s.at(1) == 6); - CHECK_THROW(s.at(2), fail_fast); + CHECK_THROWS_AS(s.at(2), fail_fast); } } -TEST(operator_function_call) +TEST_CASE("operator_function_call") { int arr[4] = {1, 2, 3, 4}; { span s = arr; CHECK(s(0) == 1); - CHECK_THROW(s(5), fail_fast); + CHECK_THROWS_AS(s(5), fail_fast); } { @@ -979,25 +980,25 @@ TEST(operator_function_call) span s = arr2d; CHECK(s(0) == 1); CHECK(s(1) == 6); - CHECK_THROW(s(2), fail_fast); + CHECK_THROWS_AS(s(2), fail_fast); } } -TEST(iterator_default_init) +TEST_CASE("iterator_default_init") { span::iterator it1; span::iterator it2; CHECK(it1 == it2); } -TEST(const_iterator_default_init) +TEST_CASE("const_iterator_default_init") { span::const_iterator it1; span::const_iterator it2; CHECK(it1 == it2); } -TEST(iterator_conversions) +TEST_CASE("iterator_conversions") { span::iterator badIt; span::const_iterator badConstIt; @@ -1019,7 +1020,7 @@ TEST(iterator_conversions) CHECK(cit3 == s.cend()); } -TEST(iterator_comparisons) +TEST_CASE("iterator_comparisons") { int a[] = {1, 2, 3, 4}; { @@ -1066,7 +1067,7 @@ TEST(iterator_comparisons) } } -TEST(begin_end) +TEST_CASE("begin_end") { { int a[] = {1, 2, 3, 4}; @@ -1092,7 +1093,7 @@ TEST(begin_end) auto beyond = s.end(); CHECK(it != beyond); - CHECK_THROW(*beyond, fail_fast); + CHECK_THROWS_AS(*beyond, fail_fast); CHECK(beyond - first == 4); CHECK(first - first == 0); @@ -1121,7 +1122,7 @@ TEST(begin_end) } } -TEST(cbegin_cend) +TEST_CASE("cbegin_cend") { { int a[] = {1, 2, 3, 4}; @@ -1147,7 +1148,7 @@ TEST(cbegin_cend) auto beyond = s.cend(); CHECK(it != beyond); - CHECK_THROW(*beyond, fail_fast); + CHECK_THROWS_AS(*beyond, fail_fast); CHECK(beyond - first == 4); CHECK(first - first == 0); @@ -1173,7 +1174,7 @@ TEST(cbegin_cend) } } -TEST(rbegin_rend) +TEST_CASE("rbegin_rend") { { int a[] = {1, 2, 3, 4}; @@ -1186,7 +1187,7 @@ TEST(rbegin_rend) auto beyond = s.rend(); CHECK(it != beyond); - CHECK_THROW(*beyond, fail_fast); + CHECK_THROWS_AS(*beyond, fail_fast); CHECK(beyond - first == 4); CHECK(first - first == 0); @@ -1215,7 +1216,7 @@ TEST(rbegin_rend) } } -TEST(crbegin_crend) +TEST_CASE("crbegin_crend") { { int a[] = {1, 2, 3, 4}; @@ -1228,7 +1229,7 @@ TEST(crbegin_crend) auto beyond = s.crend(); CHECK(it != beyond); - CHECK_THROW(*beyond, fail_fast); + CHECK_THROWS_AS(*beyond, fail_fast); CHECK(beyond - first == 4); CHECK(first - first == 0); @@ -1254,7 +1255,7 @@ TEST(crbegin_crend) } } -TEST(comparison_operators) +TEST_CASE("comparison_operators") { { span s1 = nullptr; @@ -1374,7 +1375,7 @@ TEST(comparison_operators) } } -TEST(as_bytes) +TEST_CASE("as_bytes") { int a[] = {1, 2, 3, 4}; @@ -1404,7 +1405,7 @@ TEST(as_bytes) } } -TEST(as_writeable_bytes) +TEST_CASE("as_writeable_bytes") { int a[] = {1, 2, 3, 4}; @@ -1437,7 +1438,7 @@ TEST(as_writeable_bytes) } } -TEST(fixed_size_conversions) +TEST_CASE("fixed_size_conversions") { int arr[] = {1, 2, 3, 4}; @@ -1470,7 +1471,7 @@ TEST(fixed_size_conversions) span s2 = s; static_cast(s2); }; - CHECK_THROW(f(), fail_fast); + CHECK_THROWS_AS(f(), fail_fast); } // but doing so explicitly is ok @@ -1509,7 +1510,7 @@ TEST(fixed_size_conversions) span _s4 = {arr2, 2}; static_cast(_s4); }; - CHECK_THROW(f(), fail_fast); + CHECK_THROWS_AS(f(), fail_fast); } // this should fail - we are trying to assign a small dynamic span to a fixed_size larger one @@ -1518,10 +1519,10 @@ TEST(fixed_size_conversions) span _s4 = av; static_cast(_s4); }; - CHECK_THROW(f(), fail_fast); + CHECK_THROWS_AS(f(), fail_fast); } -TEST(interop_with_std_regex) +TEST_CASE("interop_with_std_regex") { char lat[] = {'1', '2', '3', '4', '5', '6', 'E', 'F', 'G'}; span s = lat; @@ -1544,19 +1545,16 @@ TEST(interop_with_std_regex) CHECK(match[0].second == (f_it + 1)); } -TEST(interop_with_gsl_at) +TEST_CASE("interop_with_gsl_at") { int arr[5] = {1, 2, 3, 4, 5}; span s{arr}; - CHECK(at(s, 0) == 1 && at(s, 1) == 2); + CHECK((at(s, 0) == 1 && at(s, 1) == 2)); } -TEST(default_constructible) +TEST_CASE("default_constructible") { CHECK((std::is_default_constructible>::value)); CHECK((std::is_default_constructible>::value)); CHECK((!std::is_default_constructible>::value)); } -} - -int main(int, const char* []) { return UnitTest::RunAllTests(); } diff --git a/tests/strided_span_tests.cpp b/tests/strided_span_tests.cpp index bafa304..a1ecfcb 100644 --- a/tests/strided_span_tests.cpp +++ b/tests/strided_span_tests.cpp @@ -14,7 +14,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include @@ -38,720 +38,715 @@ struct DerivedClass : BaseClass }; } -SUITE(strided_span_tests) +TEST_CASE("span_section_test") { - TEST(span_section_test) - { - int a[30][4][5]; + int a[30][4][5]; - const auto av = as_multi_span(a); - const auto sub = av.section({15, 0, 0}, gsl::index<3>{2, 2, 2}); - const auto subsub = sub.section({1, 0, 0}, gsl::index<3>{1, 1, 1}); - (void) subsub; + const auto av = as_multi_span(a); + const auto sub = av.section({15, 0, 0}, gsl::index<3>{2, 2, 2}); + const auto subsub = sub.section({1, 0, 0}, gsl::index<3>{1, 1, 1}); + (void) subsub; +} + +TEST_CASE("span_section") +{ + std::vector data(5 * 10); + std::iota(begin(data), end(data), 0); + const multi_span av = as_multi_span(multi_span{data}, dim<5>(), dim<10>()); + + const strided_span av_section_1 = av.section({1, 2}, {3, 4}); + CHECK((av_section_1[{0, 0}] == 12)); + CHECK((av_section_1[{0, 1}] == 13)); + CHECK((av_section_1[{1, 0}] == 22)); + CHECK((av_section_1[{2, 3}] == 35)); + + const strided_span av_section_2 = av_section_1.section({1, 2}, {2, 2}); + CHECK((av_section_2[{0, 0}] == 24)); + CHECK((av_section_2[{0, 1}] == 25)); + CHECK((av_section_2[{1, 0}] == 34)); +} + +TEST_CASE("strided_span_constructors") +{ + // Check stride constructor + { + int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + const int carr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + + strided_span sav1{arr, {{9}, {1}}}; // T -> T + CHECK(sav1.bounds().index_bounds() == index<1>{9}); + CHECK(sav1.bounds().stride() == 1); + CHECK((sav1[0] == 1 && sav1[8] == 9)); + + strided_span sav2{carr, {{4}, {2}}}; // const T -> const T + CHECK(sav2.bounds().index_bounds() == index<1>{4}); + CHECK(sav2.bounds().strides() == index<1>{2}); + CHECK((sav2[0] == 1 && sav2[3] == 7)); + + strided_span sav3{arr, {{2, 2}, {6, 2}}}; // T -> const T + CHECK((sav3.bounds().index_bounds() == index<2>{2, 2})); + CHECK((sav3.bounds().strides() == index<2>{6, 2})); + CHECK((sav3[{0, 0}] == 1 && sav3[{0, 1}] == 3 && sav3[{1, 0}] == 7)); } - TEST(span_section) + // Check multi_span constructor { - std::vector data(5 * 10); - std::iota(begin(data), end(data), 0); - const multi_span av = as_multi_span(multi_span{data}, dim<5>(), dim<10>()); + int arr[] = {1, 2}; - const strided_span av_section_1 = av.section({1, 2}, {3, 4}); - CHECK((av_section_1[{0, 0}] == 12)); - CHECK((av_section_1[{0, 1}] == 13)); - CHECK((av_section_1[{1, 0}] == 22)); - CHECK((av_section_1[{2, 3}] == 35)); - - const strided_span av_section_2 = av_section_1.section({1, 2}, {2, 2}); - CHECK((av_section_2[{0, 0}] == 24)); - CHECK((av_section_2[{0, 1}] == 25)); - CHECK((av_section_2[{1, 0}] == 34)); - } - - TEST(strided_span_constructors) - { - // Check stride constructor + // From non-cv-qualified source { - int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - const int carr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + const multi_span src = arr; - strided_span sav1{arr, {{9}, {1}}}; // T -> T - CHECK(sav1.bounds().index_bounds() == index<1>{9}); - CHECK(sav1.bounds().stride() == 1); - CHECK(sav1[0] == 1 && sav1[8] == 9); - - strided_span sav2{carr, {{4}, {2}}}; // const T -> const T - CHECK(sav2.bounds().index_bounds() == index<1>{4}); - CHECK(sav2.bounds().strides() == index<1>{2}); - CHECK(sav2[0] == 1 && sav2[3] == 7); - - strided_span sav3{arr, {{2, 2}, {6, 2}}}; // T -> const T - CHECK((sav3.bounds().index_bounds() == index<2>{2, 2})); - CHECK((sav3.bounds().strides() == index<2>{6, 2})); - CHECK((sav3[{0, 0}] == 1 && sav3[{0, 1}] == 3 && sav3[{1, 0}] == 7)); - } - - // Check multi_span constructor - { - int arr[] = {1, 2}; - - // From non-cv-qualified source - { - const multi_span src = arr; - - strided_span sav{src, {2, 1}}; - CHECK(sav.bounds().index_bounds() == index<1>{2}); - CHECK(sav.bounds().strides() == index<1>{1}); - CHECK(sav[1] == 2); - -#if _MSC_VER > 1800 - // strided_span sav_c{ {src}, {2, 1} }; - strided_span sav_c{multi_span{src}, - strided_bounds<1>{2, 1}}; -#else - strided_span sav_c{multi_span{src}, - strided_bounds<1>{2, 1}}; -#endif - CHECK(sav_c.bounds().index_bounds() == index<1>{2}); - CHECK(sav_c.bounds().strides() == index<1>{1}); - CHECK(sav_c[1] == 2); - -#if _MSC_VER > 1800 - strided_span sav_v{src, {2, 1}}; -#else - strided_span sav_v{multi_span{src}, - strided_bounds<1>{2, 1}}; -#endif - CHECK(sav_v.bounds().index_bounds() == index<1>{2}); - CHECK(sav_v.bounds().strides() == index<1>{1}); - CHECK(sav_v[1] == 2); - -#if _MSC_VER > 1800 - strided_span sav_cv{src, {2, 1}}; -#else - strided_span sav_cv{multi_span{src}, - strided_bounds<1>{2, 1}}; -#endif - CHECK(sav_cv.bounds().index_bounds() == index<1>{2}); - CHECK(sav_cv.bounds().strides() == index<1>{1}); - CHECK(sav_cv[1] == 2); - } - - // From const-qualified source - { - const multi_span src{arr}; - - strided_span sav_c{src, {2, 1}}; - CHECK(sav_c.bounds().index_bounds() == index<1>{2}); - CHECK(sav_c.bounds().strides() == index<1>{1}); - CHECK(sav_c[1] == 2); - -#if _MSC_VER > 1800 - strided_span sav_cv{src, {2, 1}}; -#else - strided_span sav_cv{multi_span{src}, - strided_bounds<1>{2, 1}}; -#endif - - CHECK(sav_cv.bounds().index_bounds() == index<1>{2}); - CHECK(sav_cv.bounds().strides() == index<1>{1}); - CHECK(sav_cv[1] == 2); - } - - // From volatile-qualified source - { - const multi_span src{arr}; - - strided_span sav_v{src, {2, 1}}; - CHECK(sav_v.bounds().index_bounds() == index<1>{2}); - CHECK(sav_v.bounds().strides() == index<1>{1}); - CHECK(sav_v[1] == 2); - -#if _MSC_VER > 1800 - strided_span sav_cv{src, {2, 1}}; -#else - strided_span sav_cv{multi_span{src}, - strided_bounds<1>{2, 1}}; -#endif - CHECK(sav_cv.bounds().index_bounds() == index<1>{2}); - CHECK(sav_cv.bounds().strides() == index<1>{1}); - CHECK(sav_cv[1] == 2); - } - - // From cv-qualified source - { - const multi_span src{arr}; - - strided_span sav_cv{src, {2, 1}}; - CHECK(sav_cv.bounds().index_bounds() == index<1>{2}); - CHECK(sav_cv.bounds().strides() == index<1>{1}); - CHECK(sav_cv[1] == 2); - } - } - - // Check const-casting constructor - { - int arr[2] = {4, 5}; - - const multi_span av(arr, 2); - multi_span av2{av}; - CHECK(av2[1] == 5); - - static_assert( - std::is_convertible, multi_span>::value, - "ctor is not implicit!"); - - const strided_span src{arr, {2, 1}}; - strided_span sav{src}; - CHECK(sav.bounds().index_bounds() == index<1>{2}); - CHECK(sav.bounds().stride() == 1); - CHECK(sav[1] == 5); - - static_assert( - std::is_convertible, strided_span>::value, - "ctor is not implicit!"); - } - - // Check copy constructor - { - int arr1[2] = {3, 4}; - const strided_span src1{arr1, {2, 1}}; - strided_span sav1{src1}; - - CHECK(sav1.bounds().index_bounds() == index<1>{2}); - CHECK(sav1.bounds().stride() == 1); - CHECK(sav1[0] == 3); - - int arr2[6] = {1, 2, 3, 4, 5, 6}; - const strided_span src2{arr2, {{3, 2}, {2, 1}}}; - strided_span sav2{src2}; - CHECK((sav2.bounds().index_bounds() == index<2>{3, 2})); - CHECK((sav2.bounds().strides() == index<2>{2, 1})); - CHECK((sav2[{0, 0}] == 1 && sav2[{2, 0}] == 5)); - } - - // Check const-casting assignment operator - { - int arr1[2] = {1, 2}; - int arr2[6] = {3, 4, 5, 6, 7, 8}; - - const strided_span src{arr1, {{2}, {1}}}; - strided_span sav{arr2, {{3}, {2}}}; - strided_span& sav_ref = (sav = src); + strided_span sav{src, {2, 1}}; CHECK(sav.bounds().index_bounds() == index<1>{2}); CHECK(sav.bounds().strides() == index<1>{1}); - CHECK(sav[0] == 1); - CHECK(&sav_ref == &sav); - } + CHECK(sav[1] == 2); - // Check copy assignment operator - { - int arr1[2] = {3, 4}; - int arr1b[1] = {0}; - const strided_span src1{arr1, {2, 1}}; - strided_span sav1{arr1b, {1, 1}}; - strided_span& sav1_ref = (sav1 = src1); - CHECK(sav1.bounds().index_bounds() == index<1>{2}); - CHECK(sav1.bounds().strides() == index<1>{1}); - CHECK(sav1[0] == 3); - CHECK(&sav1_ref == &sav1); - - const int arr2[6] = {1, 2, 3, 4, 5, 6}; - const int arr2b[1] = {0}; - const strided_span src2{arr2, {{3, 2}, {2, 1}}}; - strided_span sav2{arr2b, {{1, 1}, {1, 1}}}; - strided_span& sav2_ref = (sav2 = src2); - CHECK((sav2.bounds().index_bounds() == index<2>{3, 2})); - CHECK((sav2.bounds().strides() == index<2>{2, 1})); - CHECK((sav2[{0, 0}] == 1 && sav2[{2, 0}] == 5)); - CHECK(&sav2_ref == &sav2); - } - } - - TEST(strided_span_slice) - { - std::vector data(5 * 10); - std::iota(begin(data), end(data), 0); - const multi_span src = - as_multi_span(multi_span{data}, dim<5>(), dim<10>()); - - const strided_span sav{src, {{5, 10}, {10, 1}}}; -#ifdef CONFIRM_COMPILATION_ERRORS - const strided_span csav{{src}, {{5, 10}, {10, 1}}}; -#endif - const strided_span csav{multi_span{src}, - {{5, 10}, {10, 1}}}; - - strided_span sav_sl = sav[2]; - CHECK(sav_sl[0] == 20); - CHECK(sav_sl[9] == 29); - - strided_span csav_sl = sav[3]; - CHECK(csav_sl[0] == 30); - CHECK(csav_sl[9] == 39); - - CHECK(sav[4][0] == 40); - CHECK(sav[4][9] == 49); - } - - TEST(strided_span_column_major) - { - // strided_span may be used to accomodate more peculiar - // use cases, such as column-major multidimensional array - // (aka. "FORTRAN" layout). - - int cm_array[3 * 5] = {1, 4, 7, 10, 13, 2, 5, 8, 11, 14, 3, 6, 9, 12, 15}; - strided_span cm_sav{cm_array, {{5, 3}, {1, 5}}}; - - // Accessing elements - CHECK((cm_sav[{0, 0}] == 1)); - CHECK((cm_sav[{0, 1}] == 2)); - CHECK((cm_sav[{1, 0}] == 4)); - CHECK((cm_sav[{4, 2}] == 15)); - - // Slice - strided_span cm_sl = cm_sav[3]; - - CHECK(cm_sl[0] == 10); - CHECK(cm_sl[1] == 11); - CHECK(cm_sl[2] == 12); - - // Section - strided_span cm_sec = cm_sav.section({2, 1}, {3, 2}); - - CHECK((cm_sec.bounds().index_bounds() == index<2>{3, 2})); - CHECK((cm_sec[{0, 0}] == 8)); - CHECK((cm_sec[{0, 1}] == 9)); - CHECK((cm_sec[{1, 0}] == 11)); - CHECK((cm_sec[{2, 1}] == 15)); - } - - TEST(strided_span_bounds) - { - int arr[] = {0, 1, 2, 3}; - multi_span av(arr); - - { - // incorrect sections - - CHECK_THROW(av.section(0, 0)[0], fail_fast); - CHECK_THROW(av.section(1, 0)[0], fail_fast); - CHECK_THROW(av.section(1, 1)[1], fail_fast); - - CHECK_THROW(av.section(2, 5), fail_fast); - CHECK_THROW(av.section(5, 2), fail_fast); - CHECK_THROW(av.section(5, 0), fail_fast); - CHECK_THROW(av.section(0, 5), fail_fast); - CHECK_THROW(av.section(5, 5), fail_fast); - } - - { - // zero stride - strided_span sav{av, {{4}, {}}}; - CHECK(sav[0] == 0); - CHECK(sav[3] == 0); - CHECK_THROW(sav[4], fail_fast); - } - - { - // zero extent - strided_span sav{av, {{}, {1}}}; - CHECK_THROW(sav[0], fail_fast); - } - - { - // zero extent and stride - strided_span sav{av, {{}, {}}}; - CHECK_THROW(sav[0], fail_fast); - } - - { - // strided array ctor with matching strided bounds - strided_span sav{arr, {4, 1}}; - CHECK(sav.bounds().index_bounds() == index<1>{4}); - CHECK(sav[3] == 3); - CHECK_THROW(sav[4], fail_fast); - } - - { - // strided array ctor with smaller strided bounds - strided_span sav{arr, {2, 1}}; - CHECK(sav.bounds().index_bounds() == index<1>{2}); - CHECK(sav[1] == 1); - CHECK_THROW(sav[2], fail_fast); - } - - { - // strided array ctor with fitting irregular bounds - strided_span sav{arr, {2, 3}}; - CHECK(sav.bounds().index_bounds() == index<1>{2}); - CHECK(sav[0] == 0); - CHECK(sav[1] == 3); - CHECK_THROW(sav[2], fail_fast); - } - - { - // bounds cross data boundaries - from static arrays - CHECK_THROW((strided_span{arr, {3, 2}}), fail_fast); - CHECK_THROW((strided_span{arr, {3, 3}}), fail_fast); - CHECK_THROW((strided_span{arr, {4, 5}}), fail_fast); - CHECK_THROW((strided_span{arr, {5, 1}}), fail_fast); - CHECK_THROW((strided_span{arr, {5, 5}}), fail_fast); - } - - { - // bounds cross data boundaries - from array view - CHECK_THROW((strided_span{av, {3, 2}}), fail_fast); - CHECK_THROW((strided_span{av, {3, 3}}), fail_fast); - CHECK_THROW((strided_span{av, {4, 5}}), fail_fast); - CHECK_THROW((strided_span{av, {5, 1}}), fail_fast); - CHECK_THROW((strided_span{av, {5, 5}}), fail_fast); - } - - { - // bounds cross data boundaries - from dynamic arrays - CHECK_THROW((strided_span{av.data(), 4, {3, 2}}), fail_fast); - CHECK_THROW((strided_span{av.data(), 4, {3, 3}}), fail_fast); - CHECK_THROW((strided_span{av.data(), 4, {4, 5}}), fail_fast); - CHECK_THROW((strided_span{av.data(), 4, {5, 1}}), fail_fast); - CHECK_THROW((strided_span{av.data(), 4, {5, 5}}), fail_fast); - CHECK_THROW((strided_span{av.data(), 2, {2, 2}}), fail_fast); - } - -#ifdef CONFIRM_COMPILATION_ERRORS - { - strided_span sav0{av.data(), {3, 2}}; - strided_span sav1{arr, {1}}; - strided_span sav2{arr, {1, 1, 1}}; - strided_span sav3{av, {1}}; - strided_span sav4{av, {1, 1, 1}}; - strided_span sav5{av.as_multi_span(dim<2>(), dim<2>()), {1}}; - strided_span sav6{av.as_multi_span(dim<2>(), dim<2>()), {1, 1, 1}}; - strided_span sav7{av.as_multi_span(dim<2>(), dim<2>()), - {{1, 1}, {1, 1}, {1, 1}}}; - - index<1> index{0, 1}; - strided_span sav8{arr, {1, {1, 1}}}; - strided_span sav9{arr, {{1, 1}, {1, 1}}}; - strided_span sav10{av, {1, {1, 1}}}; - strided_span sav11{av, {{1, 1}, {1, 1}}}; - strided_span sav12{av.as_multi_span(dim<2>(), dim<2>()), {{1}, {1}}}; - strided_span sav13{av.as_multi_span(dim<2>(), dim<2>()), {{1}, {1, 1, 1}}}; - strided_span sav14{av.as_multi_span(dim<2>(), dim<2>()), {{1, 1, 1}, {1}}}; - } -#endif - } - - TEST(strided_span_type_conversion) - { - int arr[] = {0, 1, 2, 3}; - multi_span av(arr); - - { - strided_span sav{av.data(), av.size(), {av.size() / 2, 2}}; -#ifdef CONFIRM_COMPILATION_ERRORS - strided_span lsav1 = sav.as_strided_span(); -#endif - } - { - strided_span sav{av, {av.size() / 2, 2}}; -#ifdef CONFIRM_COMPILATION_ERRORS - strided_span lsav1 = sav.as_strided_span(); -#endif - } - - multi_span bytes = as_bytes(av); - - // retype strided array with regular strides - from raw data - { - strided_bounds<2> bounds{{2, bytes.size() / 4}, {bytes.size() / 2, 1}}; - strided_span sav2{bytes.data(), bytes.size(), bounds}; - strided_span sav3 = sav2.as_strided_span(); - CHECK(sav3[0][0] == 0); - CHECK(sav3[1][0] == 2); - CHECK_THROW(sav3[1][1], fail_fast); - CHECK_THROW(sav3[0][1], fail_fast); - } - - // retype strided array with regular strides - from multi_span - { - strided_bounds<2> bounds{{2, bytes.size() / 4}, {bytes.size() / 2, 1}}; - multi_span bytes2 = - as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); - strided_span sav2{bytes2, bounds}; - strided_span sav3 = sav2.as_strided_span(); - CHECK(sav3[0][0] == 0); - CHECK(sav3[1][0] == 2); - CHECK_THROW(sav3[1][1], fail_fast); - CHECK_THROW(sav3[0][1], fail_fast); - } - - // retype strided array with not enough elements - last dimension of the array is too small - { - strided_bounds<2> bounds{{4, 2}, {4, 1}}; - multi_span bytes2 = - as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); - strided_span sav2{bytes2, bounds}; - CHECK_THROW(sav2.as_strided_span(), fail_fast); - } - - // retype strided array with not enough elements - strides are too small - { - strided_bounds<2> bounds{{4, 2}, {2, 1}}; - multi_span bytes2 = - as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); - strided_span sav2{bytes2, bounds}; - CHECK_THROW(sav2.as_strided_span(), fail_fast); - } - - // retype strided array with not enough elements - last dimension does not divide by the new - // typesize - { - strided_bounds<2> bounds{{2, 6}, {4, 1}}; - multi_span bytes2 = - as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); - strided_span sav2{bytes2, bounds}; - CHECK_THROW(sav2.as_strided_span(), fail_fast); - } - - // retype strided array with not enough elements - strides does not divide by the new - // typesize - { - strided_bounds<2> bounds{{2, 1}, {6, 1}}; - multi_span bytes2 = - as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); - strided_span sav2{bytes2, bounds}; - CHECK_THROW(sav2.as_strided_span(), fail_fast); - } - - // retype strided array with irregular strides - from raw data - { - strided_bounds<1> bounds{bytes.size() / 2, 2}; - strided_span sav2{bytes.data(), bytes.size(), bounds}; - CHECK_THROW(sav2.as_strided_span(), fail_fast); - } - - // retype strided array with irregular strides - from multi_span - { - strided_bounds<1> bounds{bytes.size() / 2, 2}; - strided_span sav2{bytes, bounds}; - CHECK_THROW(sav2.as_strided_span(), fail_fast); - } - } - - TEST(empty_strided_spans) - { - { - multi_span empty_av(nullptr); - strided_span empty_sav{empty_av, {0, 1}}; - - CHECK(empty_sav.bounds().index_bounds() == index<1>{0}); - CHECK_THROW(empty_sav[0], fail_fast); - CHECK_THROW(empty_sav.begin()[0], fail_fast); - CHECK_THROW(empty_sav.cbegin()[0], fail_fast); - - for (const auto& v : empty_sav) { - (void) v; - CHECK(false); - } - } - - { - strided_span empty_sav{nullptr, 0, {0, 1}}; - - CHECK(empty_sav.bounds().index_bounds() == index<1>{0}); - CHECK_THROW(empty_sav[0], fail_fast); - CHECK_THROW(empty_sav.begin()[0], fail_fast); - CHECK_THROW(empty_sav.cbegin()[0], fail_fast); - - for (const auto& v : empty_sav) { - (void) v; - CHECK(false); - } - } - } - - void iterate_every_other_element(multi_span av) - { - // pick every other element - - auto length = av.size() / 2; #if _MSC_VER > 1800 - auto bounds = strided_bounds<1>({length}, {2}); + // strided_span sav_c{ {src}, {2, 1} }; + strided_span sav_c{multi_span{src}, + strided_bounds<1>{2, 1}}; #else - auto bounds = strided_bounds<1>(index<1>{length}, index<1>{2}); + strided_span sav_c{multi_span{src}, + strided_bounds<1>{2, 1}}; #endif - strided_span strided(&av.data()[1], av.size() - 1, bounds); + CHECK(sav_c.bounds().index_bounds() == index<1>{2}); + CHECK(sav_c.bounds().strides() == index<1>{1}); + CHECK(sav_c[1] == 2); - CHECK(strided.size() == length); - CHECK(strided.bounds().index_bounds()[0] == length); - for (auto i = 0; i < strided.size(); ++i) { - CHECK(strided[i] == av[2 * i + 1]); +#if _MSC_VER > 1800 + strided_span sav_v{src, {2, 1}}; +#else + strided_span sav_v{multi_span{src}, + strided_bounds<1>{2, 1}}; +#endif + CHECK(sav_v.bounds().index_bounds() == index<1>{2}); + CHECK(sav_v.bounds().strides() == index<1>{1}); + CHECK(sav_v[1] == 2); + +#if _MSC_VER > 1800 + strided_span sav_cv{src, {2, 1}}; +#else + strided_span sav_cv{multi_span{src}, + strided_bounds<1>{2, 1}}; +#endif + CHECK(sav_cv.bounds().index_bounds() == index<1>{2}); + CHECK(sav_cv.bounds().strides() == index<1>{1}); + CHECK(sav_cv[1] == 2); } - int idx = 0; - for (auto num : strided) { - CHECK(num == av[2 * idx + 1]); - idx++; + // From const-qualified source + { + const multi_span src{arr}; + + strided_span sav_c{src, {2, 1}}; + CHECK(sav_c.bounds().index_bounds() == index<1>{2}); + CHECK(sav_c.bounds().strides() == index<1>{1}); + CHECK(sav_c[1] == 2); + +#if _MSC_VER > 1800 + strided_span sav_cv{src, {2, 1}}; +#else + strided_span sav_cv{multi_span{src}, + strided_bounds<1>{2, 1}}; +#endif + + CHECK(sav_cv.bounds().index_bounds() == index<1>{2}); + CHECK(sav_cv.bounds().strides() == index<1>{1}); + CHECK(sav_cv[1] == 2); + } + + // From volatile-qualified source + { + const multi_span src{arr}; + + strided_span sav_v{src, {2, 1}}; + CHECK(sav_v.bounds().index_bounds() == index<1>{2}); + CHECK(sav_v.bounds().strides() == index<1>{1}); + CHECK(sav_v[1] == 2); + +#if _MSC_VER > 1800 + strided_span sav_cv{src, {2, 1}}; +#else + strided_span sav_cv{multi_span{src}, + strided_bounds<1>{2, 1}}; +#endif + CHECK(sav_cv.bounds().index_bounds() == index<1>{2}); + CHECK(sav_cv.bounds().strides() == index<1>{1}); + CHECK(sav_cv[1] == 2); + } + + // From cv-qualified source + { + const multi_span src{arr}; + + strided_span sav_cv{src, {2, 1}}; + CHECK(sav_cv.bounds().index_bounds() == index<1>{2}); + CHECK(sav_cv.bounds().strides() == index<1>{1}); + CHECK(sav_cv[1] == 2); } } - TEST(strided_span_section_iteration) + // Check const-casting constructor { - int arr[8] = {4, 0, 5, 1, 6, 2, 7, 3}; + int arr[2] = {4, 5}; - // static bounds - { - multi_span av(arr, 8); - iterate_every_other_element(av); - } + const multi_span av(arr, 2); + multi_span av2{av}; + CHECK(av2[1] == 5); - // dynamic bounds - { - multi_span av(arr, 8); - iterate_every_other_element(av); + static_assert( + std::is_convertible, multi_span>::value, + "ctor is not implicit!"); + + const strided_span src{arr, {2, 1}}; + strided_span sav{src}; + CHECK(sav.bounds().index_bounds() == index<1>{2}); + CHECK(sav.bounds().stride() == 1); + CHECK(sav[1] == 5); + + static_assert( + std::is_convertible, strided_span>::value, + "ctor is not implicit!"); + } + + // Check copy constructor + { + int arr1[2] = {3, 4}; + const strided_span src1{arr1, {2, 1}}; + strided_span sav1{src1}; + + CHECK(sav1.bounds().index_bounds() == index<1>{2}); + CHECK(sav1.bounds().stride() == 1); + CHECK(sav1[0] == 3); + + int arr2[6] = {1, 2, 3, 4, 5, 6}; + const strided_span src2{arr2, {{3, 2}, {2, 1}}}; + strided_span sav2{src2}; + CHECK((sav2.bounds().index_bounds() == index<2>{3, 2})); + CHECK((sav2.bounds().strides() == index<2>{2, 1})); + CHECK((sav2[{0, 0}] == 1 && sav2[{2, 0}] == 5)); + } + + // Check const-casting assignment operator + { + int arr1[2] = {1, 2}; + int arr2[6] = {3, 4, 5, 6, 7, 8}; + + const strided_span src{arr1, {{2}, {1}}}; + strided_span sav{arr2, {{3}, {2}}}; + strided_span& sav_ref = (sav = src); + CHECK(sav.bounds().index_bounds() == index<1>{2}); + CHECK(sav.bounds().strides() == index<1>{1}); + CHECK(sav[0] == 1); + CHECK(&sav_ref == &sav); + } + + // Check copy assignment operator + { + int arr1[2] = {3, 4}; + int arr1b[1] = {0}; + const strided_span src1{arr1, {2, 1}}; + strided_span sav1{arr1b, {1, 1}}; + strided_span& sav1_ref = (sav1 = src1); + CHECK(sav1.bounds().index_bounds() == index<1>{2}); + CHECK(sav1.bounds().strides() == index<1>{1}); + CHECK(sav1[0] == 3); + CHECK(&sav1_ref == &sav1); + + const int arr2[6] = {1, 2, 3, 4, 5, 6}; + const int arr2b[1] = {0}; + const strided_span src2{arr2, {{3, 2}, {2, 1}}}; + strided_span sav2{arr2b, {{1, 1}, {1, 1}}}; + strided_span& sav2_ref = (sav2 = src2); + CHECK((sav2.bounds().index_bounds() == index<2>{3, 2})); + CHECK((sav2.bounds().strides() == index<2>{2, 1})); + CHECK((sav2[{0, 0}] == 1 && sav2[{2, 0}] == 5)); + CHECK(&sav2_ref == &sav2); + } +} + +TEST_CASE("strided_span_slice") +{ + std::vector data(5 * 10); + std::iota(begin(data), end(data), 0); + const multi_span src = + as_multi_span(multi_span{data}, dim<5>(), dim<10>()); + + const strided_span sav{src, {{5, 10}, {10, 1}}}; +#ifdef CONFIRM_COMPILATION_ERRORS + const strided_span csav{{src}, {{5, 10}, {10, 1}}}; +#endif + const strided_span csav{multi_span{src}, + {{5, 10}, {10, 1}}}; + + strided_span sav_sl = sav[2]; + CHECK(sav_sl[0] == 20); + CHECK(sav_sl[9] == 29); + + strided_span csav_sl = sav[3]; + CHECK(csav_sl[0] == 30); + CHECK(csav_sl[9] == 39); + + CHECK(sav[4][0] == 40); + CHECK(sav[4][9] == 49); +} + +TEST_CASE("strided_span_column_major") +{ + // strided_span may be used to accomodate more peculiar + // use cases, such as column-major multidimensional array + // (aka. "FORTRAN" layout). + + int cm_array[3 * 5] = {1, 4, 7, 10, 13, 2, 5, 8, 11, 14, 3, 6, 9, 12, 15}; + strided_span cm_sav{cm_array, {{5, 3}, {1, 5}}}; + + // Accessing elements + CHECK((cm_sav[{0, 0}] == 1)); + CHECK((cm_sav[{0, 1}] == 2)); + CHECK((cm_sav[{1, 0}] == 4)); + CHECK((cm_sav[{4, 2}] == 15)); + + // Slice + strided_span cm_sl = cm_sav[3]; + + CHECK(cm_sl[0] == 10); + CHECK(cm_sl[1] == 11); + CHECK(cm_sl[2] == 12); + + // Section + strided_span cm_sec = cm_sav.section({2, 1}, {3, 2}); + + CHECK((cm_sec.bounds().index_bounds() == index<2>{3, 2})); + CHECK((cm_sec[{0, 0}] == 8)); + CHECK((cm_sec[{0, 1}] == 9)); + CHECK((cm_sec[{1, 0}] == 11)); + CHECK((cm_sec[{2, 1}] == 15)); +} + +TEST_CASE("strided_span_bounds") +{ + int arr[] = {0, 1, 2, 3}; + multi_span av(arr); + + { + // incorrect sections + + CHECK_THROWS_AS(av.section(0, 0)[0], fail_fast); + CHECK_THROWS_AS(av.section(1, 0)[0], fail_fast); + CHECK_THROWS_AS(av.section(1, 1)[1], fail_fast); + + CHECK_THROWS_AS(av.section(2, 5), fail_fast); + CHECK_THROWS_AS(av.section(5, 2), fail_fast); + CHECK_THROWS_AS(av.section(5, 0), fail_fast); + CHECK_THROWS_AS(av.section(0, 5), fail_fast); + CHECK_THROWS_AS(av.section(5, 5), fail_fast); + } + + { + // zero stride + strided_span sav{av, {{4}, {}}}; + CHECK(sav[0] == 0); + CHECK(sav[3] == 0); + CHECK_THROWS_AS(sav[4], fail_fast); + } + + { + // zero extent + strided_span sav{av, {{}, {1}}}; + CHECK_THROWS_AS(sav[0], fail_fast); + } + + { + // zero extent and stride + strided_span sav{av, {{}, {}}}; + CHECK_THROWS_AS(sav[0], fail_fast); + } + + { + // strided array ctor with matching strided bounds + strided_span sav{arr, {4, 1}}; + CHECK(sav.bounds().index_bounds() == index<1>{4}); + CHECK(sav[3] == 3); + CHECK_THROWS_AS(sav[4], fail_fast); + } + + { + // strided array ctor with smaller strided bounds + strided_span sav{arr, {2, 1}}; + CHECK(sav.bounds().index_bounds() == index<1>{2}); + CHECK(sav[1] == 1); + CHECK_THROWS_AS(sav[2], fail_fast); + } + + { + // strided array ctor with fitting irregular bounds + strided_span sav{arr, {2, 3}}; + CHECK(sav.bounds().index_bounds() == index<1>{2}); + CHECK(sav[0] == 0); + CHECK(sav[1] == 3); + CHECK_THROWS_AS(sav[2], fail_fast); + } + + { + // bounds cross data boundaries - from static arrays + CHECK_THROWS_AS((strided_span{arr, {3, 2}}), fail_fast); + CHECK_THROWS_AS((strided_span{arr, {3, 3}}), fail_fast); + CHECK_THROWS_AS((strided_span{arr, {4, 5}}), fail_fast); + CHECK_THROWS_AS((strided_span{arr, {5, 1}}), fail_fast); + CHECK_THROWS_AS((strided_span{arr, {5, 5}}), fail_fast); + } + + { + // bounds cross data boundaries - from array view + CHECK_THROWS_AS((strided_span{av, {3, 2}}), fail_fast); + CHECK_THROWS_AS((strided_span{av, {3, 3}}), fail_fast); + CHECK_THROWS_AS((strided_span{av, {4, 5}}), fail_fast); + CHECK_THROWS_AS((strided_span{av, {5, 1}}), fail_fast); + CHECK_THROWS_AS((strided_span{av, {5, 5}}), fail_fast); + } + + { + // bounds cross data boundaries - from dynamic arrays + CHECK_THROWS_AS((strided_span{av.data(), 4, {3, 2}}), fail_fast); + CHECK_THROWS_AS((strided_span{av.data(), 4, {3, 3}}), fail_fast); + CHECK_THROWS_AS((strided_span{av.data(), 4, {4, 5}}), fail_fast); + CHECK_THROWS_AS((strided_span{av.data(), 4, {5, 1}}), fail_fast); + CHECK_THROWS_AS((strided_span{av.data(), 4, {5, 5}}), fail_fast); + CHECK_THROWS_AS((strided_span{av.data(), 2, {2, 2}}), fail_fast); + } + +#ifdef CONFIRM_COMPILATION_ERRORS + { + strided_span sav0{av.data(), {3, 2}}; + strided_span sav1{arr, {1}}; + strided_span sav2{arr, {1, 1, 1}}; + strided_span sav3{av, {1}}; + strided_span sav4{av, {1, 1, 1}}; + strided_span sav5{av.as_multi_span(dim<2>(), dim<2>()), {1}}; + strided_span sav6{av.as_multi_span(dim<2>(), dim<2>()), {1, 1, 1}}; + strided_span sav7{av.as_multi_span(dim<2>(), dim<2>()), + {{1, 1}, {1, 1}, {1, 1}}}; + + index<1> index{0, 1}; + strided_span sav8{arr, {1, {1, 1}}}; + strided_span sav9{arr, {{1, 1}, {1, 1}}}; + strided_span sav10{av, {1, {1, 1}}}; + strided_span sav11{av, {{1, 1}, {1, 1}}}; + strided_span sav12{av.as_multi_span(dim<2>(), dim<2>()), {{1}, {1}}}; + strided_span sav13{av.as_multi_span(dim<2>(), dim<2>()), {{1}, {1, 1, 1}}}; + strided_span sav14{av.as_multi_span(dim<2>(), dim<2>()), {{1, 1, 1}, {1}}}; + } +#endif +} + +TEST_CASE("strided_span_type_conversion") +{ + int arr[] = {0, 1, 2, 3}; + multi_span av(arr); + + { + strided_span sav{av.data(), av.size(), {av.size() / 2, 2}}; +#ifdef CONFIRM_COMPILATION_ERRORS + strided_span lsav1 = sav.as_strided_span(); +#endif + } + { + strided_span sav{av, {av.size() / 2, 2}}; +#ifdef CONFIRM_COMPILATION_ERRORS + strided_span lsav1 = sav.as_strided_span(); +#endif + } + + multi_span bytes = as_bytes(av); + + // retype strided array with regular strides - from raw data + { + strided_bounds<2> bounds{{2, bytes.size() / 4}, {bytes.size() / 2, 1}}; + strided_span sav2{bytes.data(), bytes.size(), bounds}; + strided_span sav3 = sav2.as_strided_span(); + CHECK(sav3[0][0] == 0); + CHECK(sav3[1][0] == 2); + CHECK_THROWS_AS(sav3[1][1], fail_fast); + CHECK_THROWS_AS(sav3[0][1], fail_fast); + } + + // retype strided array with regular strides - from multi_span + { + strided_bounds<2> bounds{{2, bytes.size() / 4}, {bytes.size() / 2, 1}}; + multi_span bytes2 = + as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); + strided_span sav2{bytes2, bounds}; + strided_span sav3 = sav2.as_strided_span(); + CHECK(sav3[0][0] == 0); + CHECK(sav3[1][0] == 2); + CHECK_THROWS_AS(sav3[1][1], fail_fast); + CHECK_THROWS_AS(sav3[0][1], fail_fast); + } + + // retype strided array with not enough elements - last dimension of the array is too small + { + strided_bounds<2> bounds{{4, 2}, {4, 1}}; + multi_span bytes2 = + as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); + strided_span sav2{bytes2, bounds}; + CHECK_THROWS_AS(sav2.as_strided_span(), fail_fast); + } + + // retype strided array with not enough elements - strides are too small + { + strided_bounds<2> bounds{{4, 2}, {2, 1}}; + multi_span bytes2 = + as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); + strided_span sav2{bytes2, bounds}; + CHECK_THROWS_AS(sav2.as_strided_span(), fail_fast); + } + + // retype strided array with not enough elements - last dimension does not divide by the new + // typesize + { + strided_bounds<2> bounds{{2, 6}, {4, 1}}; + multi_span bytes2 = + as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); + strided_span sav2{bytes2, bounds}; + CHECK_THROWS_AS(sav2.as_strided_span(), fail_fast); + } + + // retype strided array with not enough elements - strides does not divide by the new + // typesize + { + strided_bounds<2> bounds{{2, 1}, {6, 1}}; + multi_span bytes2 = + as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); + strided_span sav2{bytes2, bounds}; + CHECK_THROWS_AS(sav2.as_strided_span(), fail_fast); + } + + // retype strided array with irregular strides - from raw data + { + strided_bounds<1> bounds{bytes.size() / 2, 2}; + strided_span sav2{bytes.data(), bytes.size(), bounds}; + CHECK_THROWS_AS(sav2.as_strided_span(), fail_fast); + } + + // retype strided array with irregular strides - from multi_span + { + strided_bounds<1> bounds{bytes.size() / 2, 2}; + strided_span sav2{bytes, bounds}; + CHECK_THROWS_AS(sav2.as_strided_span(), fail_fast); + } +} + +TEST_CASE("empty_strided_spans") +{ + { + multi_span empty_av(nullptr); + strided_span empty_sav{empty_av, {0, 1}}; + + CHECK(empty_sav.bounds().index_bounds() == index<1>{0}); + CHECK_THROWS_AS(empty_sav[0], fail_fast); + CHECK_THROWS_AS(empty_sav.begin()[0], fail_fast); + CHECK_THROWS_AS(empty_sav.cbegin()[0], fail_fast); + + for (const auto& v : empty_sav) { + (void) v; + CHECK(false); } } - TEST(dynamic_strided_span_section_iteration) { - auto arr = new int[8]; - for (int i = 0; i < 4; ++i) { - arr[2 * i] = 4 + i; - arr[2 * i + 1] = i; - } + strided_span empty_sav{nullptr, 0, {0, 1}}; - auto av = as_multi_span(arr, 8); - iterate_every_other_element(av); + CHECK(empty_sav.bounds().index_bounds() == index<1>{0}); + CHECK_THROWS_AS(empty_sav[0], fail_fast); + CHECK_THROWS_AS(empty_sav.begin()[0], fail_fast); + CHECK_THROWS_AS(empty_sav.cbegin()[0], fail_fast); - delete[] arr; - } - - void iterate_second_slice(multi_span av) - { - const int expected[6] = {2, 3, 10, 11, 18, 19}; - auto section = av.section({0, 1, 0}, {3, 1, 2}); - - for (auto i = 0; i < section.extent<0>(); ++i) { - for (auto j = 0; j < section.extent<1>(); ++j) - for (auto k = 0; k < section.extent<2>(); ++k) { - auto idx = index<3>{i, j, k}; // avoid braces in the CHECK macro - CHECK(section[idx] == expected[2 * i + 2 * j + k]); - } - } - - for (auto i = 0; i < section.extent<0>(); ++i) { - for (auto j = 0; j < section.extent<1>(); ++j) - for (auto k = 0; k < section.extent<2>(); ++k) - CHECK(section[i][j][k] == expected[2 * i + 2 * j + k]); - } - - int i = 0; - for (const auto num : section) { - CHECK(num == expected[i]); - i++; - } - } - - TEST(strided_span_section_iteration_3d) - { - int arr[3][4][2]{}; - for (auto i = 0; i < 3; ++i) { - for (auto j = 0; j < 4; ++j) - for (auto k = 0; k < 2; ++k) arr[i][j][k] = 8 * i + 2 * j + k; - } - - { - multi_span av = arr; - iterate_second_slice(av); - } - } - - TEST(dynamic_strided_span_section_iteration_3d) - { - const auto height = 12, width = 2; - const auto size = height * width; - - auto arr = new int[static_cast(size)]; - for (auto i = 0; i < size; ++i) { - arr[i] = i; - } - - { - auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim<4>(), dim<2>()); - iterate_second_slice(av); - } - - { - auto av = as_multi_span(as_multi_span(arr, 24), dim(3), dim<4>(), dim<2>()); - iterate_second_slice(av); - } - - { - auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim(4), dim<2>()); - iterate_second_slice(av); - } - - { - auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim<4>(), dim(2)); - iterate_second_slice(av); - } - delete[] arr; - } - - TEST(strided_span_conversion) - { - // get an multi_span of 'c' values from the list of X's - - struct X - { - int a; - int b; - int c; - }; - - X arr[4] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}}; - - int s = sizeof(int) / sizeof(byte); - auto d2 = 3 * s; - auto d1 = narrow_cast(sizeof(int)) * 12 / d2; - - // convert to 4x12 array of bytes - auto av = as_multi_span(as_bytes(as_multi_span(arr, 4)), dim(d1), dim(d2)); - - CHECK(av.bounds().index_bounds()[0] == 4); - CHECK(av.bounds().index_bounds()[1] == 12); - - // get the last 4 columns - auto section = av.section({0, 2 * s}, {4, s}); // { { arr[0].c[0], arr[0].c[1], arr[0].c[2], - // arr[0].c[3] } , { arr[1].c[0], ... } , ... - // } - - // convert to array 4x1 array of integers - auto cs = section.as_strided_span(); // { { arr[0].c }, {arr[1].c } , ... } - - CHECK(cs.bounds().index_bounds()[0] == 4); - CHECK(cs.bounds().index_bounds()[1] == 1); - - // transpose to 1x4 array - strided_bounds<2> reverse_bounds{ - {cs.bounds().index_bounds()[1], cs.bounds().index_bounds()[0]}, - {cs.bounds().strides()[1], cs.bounds().strides()[0]}}; - - strided_span transposed{cs.data(), cs.bounds().total_size(), reverse_bounds}; - - // slice to get a one-dimensional array of c's - strided_span result = transposed[0]; - - CHECK(result.bounds().index_bounds()[0] == 4); - CHECK_THROW(result.bounds().index_bounds()[1], fail_fast); - - int i = 0; - for (auto& num : result) { - CHECK(num == arr[i].c); - i++; + for (const auto& v : empty_sav) { + (void) v; + CHECK(false); } } } -int main(int, const char* []) { return UnitTest::RunAllTests(); } +void iterate_every_other_element(multi_span av) +{ + // pick every other element + + auto length = av.size() / 2; +#if _MSC_VER > 1800 + auto bounds = strided_bounds<1>({length}, {2}); +#else + auto bounds = strided_bounds<1>(index<1>{length}, index<1>{2}); +#endif + strided_span strided(&av.data()[1], av.size() - 1, bounds); + + CHECK(strided.size() == length); + CHECK(strided.bounds().index_bounds()[0] == length); + for (auto i = 0; i < strided.size(); ++i) { + CHECK(strided[i] == av[2 * i + 1]); + } + + int idx = 0; + for (auto num : strided) { + CHECK(num == av[2 * idx + 1]); + idx++; + } +} + +TEST_CASE("strided_span_section_iteration") +{ + int arr[8] = {4, 0, 5, 1, 6, 2, 7, 3}; + + // static bounds + { + multi_span av(arr, 8); + iterate_every_other_element(av); + } + + // dynamic bounds + { + multi_span av(arr, 8); + iterate_every_other_element(av); + } +} + +TEST_CASE("dynamic_strided_span_section_iteration") +{ + auto arr = new int[8]; + for (int i = 0; i < 4; ++i) { + arr[2 * i] = 4 + i; + arr[2 * i + 1] = i; + } + + auto av = as_multi_span(arr, 8); + iterate_every_other_element(av); + + delete[] arr; +} + +void iterate_second_slice(multi_span av) +{ + const int expected[6] = {2, 3, 10, 11, 18, 19}; + auto section = av.section({0, 1, 0}, {3, 1, 2}); + + for (auto i = 0; i < section.extent<0>(); ++i) { + for (auto j = 0; j < section.extent<1>(); ++j) + for (auto k = 0; k < section.extent<2>(); ++k) { + auto idx = index<3>{i, j, k}; // avoid braces in the CHECK macro + CHECK(section[idx] == expected[2 * i + 2 * j + k]); + } + } + + for (auto i = 0; i < section.extent<0>(); ++i) { + for (auto j = 0; j < section.extent<1>(); ++j) + for (auto k = 0; k < section.extent<2>(); ++k) + CHECK(section[i][j][k] == expected[2 * i + 2 * j + k]); + } + + int i = 0; + for (const auto num : section) { + CHECK(num == expected[i]); + i++; + } +} + +TEST_CASE("strided_span_section_iteration_3d") +{ + int arr[3][4][2]{}; + for (auto i = 0; i < 3; ++i) { + for (auto j = 0; j < 4; ++j) + for (auto k = 0; k < 2; ++k) arr[i][j][k] = 8 * i + 2 * j + k; + } + + { + multi_span av = arr; + iterate_second_slice(av); + } +} + +TEST_CASE("dynamic_strided_span_section_iteration_3d") +{ + const auto height = 12, width = 2; + const auto size = height * width; + + auto arr = new int[static_cast(size)]; + for (auto i = 0; i < size; ++i) { + arr[i] = i; + } + + { + auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim<4>(), dim<2>()); + iterate_second_slice(av); + } + + { + auto av = as_multi_span(as_multi_span(arr, 24), dim(3), dim<4>(), dim<2>()); + iterate_second_slice(av); + } + + { + auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim(4), dim<2>()); + iterate_second_slice(av); + } + + { + auto av = as_multi_span(as_multi_span(arr, 24), dim<3>(), dim<4>(), dim(2)); + iterate_second_slice(av); + } + delete[] arr; +} + +TEST_CASE("strided_span_conversion") +{ + // get an multi_span of 'c' values from the list of X's + + struct X + { + int a; + int b; + int c; + }; + + X arr[4] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}}; + + int s = sizeof(int) / sizeof(byte); + auto d2 = 3 * s; + auto d1 = narrow_cast(sizeof(int)) * 12 / d2; + + // convert to 4x12 array of bytes + auto av = as_multi_span(as_bytes(as_multi_span(arr, 4)), dim(d1), dim(d2)); + + CHECK(av.bounds().index_bounds()[0] == 4); + CHECK(av.bounds().index_bounds()[1] == 12); + + // get the last 4 columns + auto section = av.section({0, 2 * s}, {4, s}); // { { arr[0].c[0], arr[0].c[1], arr[0].c[2], + // arr[0].c[3] } , { arr[1].c[0], ... } , ... + // } + + // convert to array 4x1 array of integers + auto cs = section.as_strided_span(); // { { arr[0].c }, {arr[1].c } , ... } + + CHECK(cs.bounds().index_bounds()[0] == 4); + CHECK(cs.bounds().index_bounds()[1] == 1); + + // transpose to 1x4 array + strided_bounds<2> reverse_bounds{ + {cs.bounds().index_bounds()[1], cs.bounds().index_bounds()[0]}, + {cs.bounds().strides()[1], cs.bounds().strides()[0]}}; + + strided_span transposed{cs.data(), cs.bounds().total_size(), reverse_bounds}; + + // slice to get a one-dimensional array of c's + strided_span result = transposed[0]; + + CHECK(result.bounds().index_bounds()[0] == 4); + CHECK_THROWS_AS(result.bounds().index_bounds()[1], fail_fast); + + int i = 0; + for (auto& num : result) { + CHECK(num == arr[i].c); + i++; + } +} diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index efaf0d2..229a117 100644 --- a/tests/string_span_tests.cpp +++ b/tests/string_span_tests.cpp @@ -14,7 +14,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include //owner #include @@ -26,944 +26,938 @@ using namespace std; using namespace gsl; -SUITE(string_span_tests) +TEST_CASE("TestLiteralConstruction") { - - TEST(TestLiteralConstruction) - { - cwstring_span<> v = ensure_z(L"Hello"); - CHECK(5 == v.length()); + cwstring_span<> v = ensure_z(L"Hello"); + CHECK(5 == v.length()); #ifdef CONFIRM_COMPILATION_ERRORS - wstring_span<> v2 = ensure0(L"Hello"); + wstring_span<> v2 = ensure0(L"Hello"); #endif - } +} + +TEST_CASE("TestConstructFromStdString") +{ + std::string s = "Hello there world"; + cstring_span<> v = s; + CHECK(v.length() == static_cast::index_type>(s.length())); +} + +TEST_CASE("TestConstructFromStdVector") +{ + std::vector vec(5, 'h'); + string_span<> v{vec}; + CHECK(v.length() == static_cast::index_type>(vec.size())); +} + +TEST_CASE("TestStackArrayConstruction") +{ + wchar_t stack_string[] = L"Hello"; - TEST(TestConstructFromStdString) { - std::string s = "Hello there world"; - cstring_span<> v = s; - CHECK(v.length() == static_cast::index_type>(s.length())); - } - - TEST(TestConstructFromStdVector) - { - std::vector vec(5, 'h'); - string_span<> v{vec}; - CHECK(v.length() == static_cast::index_type>(vec.size())); - } - - TEST(TestStackArrayConstruction) - { - wchar_t stack_string[] = L"Hello"; - - { - cwstring_span<> v = ensure_z(stack_string); - CHECK(v.length() == 5); - } - - { - cwstring_span<> v = stack_string; - CHECK(v.length() == 5); - } - - { - wstring_span<> v = ensure_z(stack_string); - CHECK(v.length() == 5); - } - - { - wstring_span<> v = stack_string; - CHECK(v.length() == 5); - } - } - - TEST(TestConstructFromConstCharPointer) - { - const char* s = "Hello"; - cstring_span<> v = ensure_z(s); + cwstring_span<> v = ensure_z(stack_string); CHECK(v.length() == 5); } - TEST(TestConversionToConst) { - char stack_string[] = "Hello"; - string_span<> v = ensure_z(stack_string); - cstring_span<> v2 = v; - CHECK(v.length() == v2.length()); + cwstring_span<> v = stack_string; + CHECK(v.length() == 5); } - TEST(TestConversionFromConst) { - char stack_string[] = "Hello"; - cstring_span<> v = ensure_z(stack_string); - (void) v; -#ifdef CONFIRM_COMPILATION_ERRORS - string_span<> v2 = v; - string_span<> v3 = "Hello"; -#endif + wstring_span<> v = ensure_z(stack_string); + CHECK(v.length() == 5); } - TEST(TestToString) { - auto s = gsl::to_string(cstring_span<>{}); - CHECK(s.length() == 0); + wstring_span<> v = stack_string; + CHECK(v.length() == 5); + } +} - char stack_string[] = "Hello"; - cstring_span<> v = ensure_z(stack_string); - auto s2 = gsl::to_string(v); - CHECK(static_cast::index_type>(s2.length()) == v.length()); - CHECK(s2.length() == 5); +TEST_CASE("TestConstructFromConstCharPointer") +{ + const char* s = "Hello"; + cstring_span<> v = ensure_z(s); + CHECK(v.length() == 5); +} + +TEST_CASE("TestConversionToConst") +{ + char stack_string[] = "Hello"; + string_span<> v = ensure_z(stack_string); + cstring_span<> v2 = v; + CHECK(v.length() == v2.length()); +} + +TEST_CASE("TestConversionFromConst") +{ + char stack_string[] = "Hello"; + cstring_span<> v = ensure_z(stack_string); + (void) v; +#ifdef CONFIRM_COMPILATION_ERRORS + string_span<> v2 = v; + string_span<> v3 = "Hello"; +#endif +} + +TEST_CASE("TestToString") +{ + auto s = gsl::to_string(cstring_span<>{}); + CHECK(s.length() == 0); + + char stack_string[] = "Hello"; + cstring_span<> v = ensure_z(stack_string); + auto s2 = gsl::to_string(v); + CHECK(static_cast::index_type>(s2.length()) == v.length()); + CHECK(s2.length() == 5); +} + +TEST_CASE("TestToBasicString") +{ + auto s = gsl::to_basic_string, ::std::allocator>( + cstring_span<>{}); + CHECK(s.length() == 0); + + char stack_string[] = "Hello"; + cstring_span<> v = ensure_z(stack_string); + auto s2 = gsl::to_basic_string, ::std::allocator>(v); + CHECK(static_cast::index_type>(s2.length()) == v.length()); + CHECK(s2.length() == 5); +} + +TEST_CASE("EqualityAndImplicitConstructors") +{ + { + cstring_span<> span = "Hello"; + cstring_span<> span1; + + // comparison to empty span + CHECK(span1 != span); + CHECK(span != span1); } - TEST(TestToBasicString) { - auto s = gsl::to_basic_string, ::std::allocator>( - cstring_span<>{}); - CHECK(s.length() == 0); + cstring_span<> span = "Hello"; + cstring_span<> span1 = "Hello1"; - char stack_string[] = "Hello"; - cstring_span<> v = ensure_z(stack_string); - auto s2 = gsl::to_basic_string, ::std::allocator>(v); - CHECK(static_cast::index_type>(s2.length()) == v.length()); - CHECK(s2.length() == 5); + // comparison to different span + CHECK(span1 != span); + CHECK(span != span1); } - TEST(EqualityAndImplicitConstructors) { - { - cstring_span<> span = "Hello"; - cstring_span<> span1; + cstring_span<> span = "Hello"; - // comparison to empty span - CHECK(span1 != span); - CHECK(span != span1); - } + const char ar[] = {'H', 'e', 'l', 'l', 'o'}; + const char ar1[] = "Hello"; + const char ar2[10] = "Hello"; + const char* ptr = "Hello"; + const std::string str = "Hello"; + const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + gsl::span sp = ensure_z("Hello"); - { - cstring_span<> span = "Hello"; - cstring_span<> span1 = "Hello1"; + // comparison to literal + CHECK(span == cstring_span<>("Hello")); - // comparison to different span - CHECK(span1 != span); - CHECK(span != span1); - } + // comparison to static array with no null termination + CHECK(span == cstring_span<>(ar)); - { - cstring_span<> span = "Hello"; + // comparison to static array with null at the end + CHECK(span == cstring_span<>(ar1)); - const char ar[] = {'H', 'e', 'l', 'l', 'o'}; - const char ar1[] = "Hello"; - const char ar2[10] = "Hello"; - const char* ptr = "Hello"; - const std::string str = "Hello"; - const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - gsl::span sp = ensure_z("Hello"); + // comparison to static array with null in the middle + CHECK(span == cstring_span<>(ar2)); - // comparison to literal - CHECK(span == cstring_span<>("Hello")); + // comparison to null-terminated c string + CHECK(span == cstring_span<>(ptr, 5)); - // comparison to static array with no null termination - CHECK(span == cstring_span<>(ar)); + // comparison to string + CHECK(span == cstring_span<>(str)); - // comparison to static array with null at the end - CHECK(span == cstring_span<>(ar1)); + // comparison to vector of charaters with no null termination + CHECK(span == cstring_span<>(vec)); - // comparison to static array with null in the middle - CHECK(span == cstring_span<>(ar2)); + // comparison to span + CHECK(span == cstring_span<>(sp)); - // comparison to null-terminated c string - CHECK(span == cstring_span<>(ptr, 5)); - - // comparison to string - CHECK(span == cstring_span<>(str)); - - // comparison to vector of charaters with no null termination - CHECK(span == cstring_span<>(vec)); - - // comparison to span - CHECK(span == cstring_span<>(sp)); - - // comparison to string_span - CHECK(span == span); - } - - { - char ar[] = {'H', 'e', 'l', 'l', 'o'}; - - string_span<> span = ar; - - char ar1[] = "Hello"; - char ar2[10] = "Hello"; - char* ptr = ar; - std::string str = "Hello"; - std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - gsl::span sp = ensure_z(ar1); - - // comparison to static array with no null termination - CHECK(span == string_span<>(ar)); - - // comparison to static array with null at the end - CHECK(span == string_span<>(ar1)); - - // comparison to static array with null in the middle - CHECK(span == string_span<>(ar2)); - - // comparison to null-terminated c string - CHECK(span == string_span<>(ptr, 5)); - - // comparison to string - CHECK(span == string_span<>(str)); - - // comparison to vector of charaters with no null termination - CHECK(span == string_span<>(vec)); - - // comparison to span - CHECK(span == string_span<>(sp)); - - // comparison to string_span - CHECK(span == span); - } - - { - const char ar[] = {'H', 'e', 'l', 'l', 'o'}; - const char ar1[] = "Hello"; - const char ar2[10] = "Hello"; - const std::string str = "Hello"; - const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - const gsl::span sp = ensure_z("Hello"); - - cstring_span<> span = "Hello"; - - // const span, const other type - - CHECK(span == "Hello"); - CHECK(span == ar); - CHECK(span == ar1); - CHECK(span == ar2); -#ifdef CONFIRM_COMPILATION_ERRORS - const char* ptr = "Hello"; - CHECK(span == ptr); -#endif - CHECK(span == str); - CHECK(span == vec); - CHECK(span == sp); - - CHECK("Hello" == span); - CHECK(ar == span); - CHECK(ar1 == span); - CHECK(ar2 == span); -#ifdef CONFIRM_COMPILATION_ERRORS - CHECK(ptr == span); -#endif - CHECK(str == span); - CHECK(vec == span); - CHECK(sp == span); - - // const span, non-const other type - - char _ar[] = {'H', 'e', 'l', 'l', 'o'}; - char _ar1[] = "Hello"; - char _ar2[10] = "Hello"; - char* _ptr = _ar; - std::string _str = "Hello"; - std::vector _vec = {'H', 'e', 'l', 'l', 'o'}; - gsl::span _sp{_ar, 5}; - - CHECK(span == _ar); - CHECK(span == _ar1); - CHECK(span == _ar2); -#ifdef CONFIRM_COMPILATION_ERRORS - CHECK(span == _ptr); -#endif - CHECK(span == _str); - CHECK(span == _vec); - CHECK(span == _sp); - - CHECK(_ar == span); - CHECK(_ar1 == span); - CHECK(_ar2 == span); -#ifdef CONFIRM_COMPILATION_ERRORS - CHECK(_ptr == span); -#endif - CHECK(_str == span); - CHECK(_vec == span); - CHECK(_sp == span); - - string_span<> _span{_ptr, 5}; - - // non-const span, non-const other type - - CHECK(_span == _ar); - CHECK(_span == _ar1); - CHECK(_span == _ar2); -#ifdef CONFIRM_COMPILATION_ERRORS - CHECK(_span == _ptr); -#endif - CHECK(_span == _str); - CHECK(_span == _vec); - CHECK(_span == _sp); - - CHECK(_ar == _span); - CHECK(_ar1 == _span); - CHECK(_ar2 == _span); -#ifdef CONFIRM_COMPILATION_ERRORS - CHECK(_ptr == _span); -#endif - CHECK(_str == _span); - CHECK(_vec == _span); - CHECK(_sp == _span); - - // non-const span, const other type - - CHECK(_span == "Hello"); - CHECK(_span == ar); - CHECK(_span == ar1); - CHECK(_span == ar2); -#ifdef CONFIRM_COMPILATION_ERRORS - CHECK(_span == ptr); -#endif - CHECK(_span == str); - CHECK(_span == vec); - CHECK(_span == sp); - - CHECK("Hello" == _span); - CHECK(ar == _span); - CHECK(ar1 == _span); - CHECK(ar2 == _span); -#ifdef CONFIRM_COMPILATION_ERRORS - CHECK(ptr == _span); -#endif - CHECK(str == _span); - CHECK(vec == _span); - CHECK(sp == _span); - - // two spans - - CHECK(_span == span); - CHECK(span == _span); - } - - { - std::vector str1 = {'H', 'e', 'l', 'l', 'o'}; - cstring_span<> span1 = str1; - std::vector str2 = std::move(str1); - cstring_span<> span2 = str2; - - // comparison of spans from the same vector before and after move (ok) - CHECK(span1 == span2); - } + // comparison to string_span + CHECK(span == span); } - TEST(ComparisonAndImplicitConstructors) { - { - cstring_span<> span = "Hello"; + char ar[] = {'H', 'e', 'l', 'l', 'o'}; - const char ar[] = {'H', 'e', 'l', 'l', 'o'}; - const char ar1[] = "Hello"; - const char ar2[10] = "Hello"; - const char* ptr = "Hello"; - const std::string str = "Hello"; - const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + string_span<> span = ar; - // comparison to literal - CHECK(span < cstring_span<>("Helloo")); - CHECK(span > cstring_span<>("Hell")); + char ar1[] = "Hello"; + char ar2[10] = "Hello"; + char* ptr = ar; + std::string str = "Hello"; + std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + gsl::span sp = ensure_z(ar1); - // comparison to static array with no null termination - CHECK(span >= cstring_span<>(ar)); + // comparison to static array with no null termination + CHECK(span == string_span<>(ar)); - // comparison to static array with null at the end - CHECK(span <= cstring_span<>(ar1)); + // comparison to static array with null at the end + CHECK(span == string_span<>(ar1)); - // comparison to static array with null in the middle - CHECK(span >= cstring_span<>(ar2)); + // comparison to static array with null in the middle + CHECK(span == string_span<>(ar2)); - // comparison to null-terminated c string - CHECK(span <= cstring_span<>(ptr, 5)); + // comparison to null-terminated c string + CHECK(span == string_span<>(ptr, 5)); - // comparison to string - CHECK(span >= cstring_span<>(str)); + // comparison to string + CHECK(span == string_span<>(str)); - // comparison to vector of charaters with no null termination - CHECK(span <= cstring_span<>(vec)); - } + // comparison to vector of charaters with no null termination + CHECK(span == string_span<>(vec)); - { - char ar[] = {'H', 'e', 'l', 'l', 'o'}; + // comparison to span + CHECK(span == string_span<>(sp)); - string_span<> span = ar; - - char larr[] = "Hell"; - char rarr[] = "Helloo"; - - char ar1[] = "Hello"; - char ar2[10] = "Hello"; - char* ptr = ar; - std::string str = "Hello"; - std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - - // comparison to static array with no null termination - CHECK(span <= string_span<>(ar)); - CHECK(span < string_span<>(rarr)); - CHECK(span > string_span<>(larr)); - - // comparison to static array with null at the end - CHECK(span >= string_span<>(ar1)); - - // comparison to static array with null in the middle - CHECK(span <= string_span<>(ar2)); - - // comparison to null-terminated c string - CHECK(span >= string_span<>(ptr, 5)); - - // comparison to string - CHECK(span <= string_span<>(str)); - - // comparison to vector of charaters with no null termination - CHECK(span >= string_span<>(vec)); - } - } - TEST(ConstrutorsEnsureZ) - { - // remove z from literals - { - cstring_span<> sp = "hello"; - CHECK((sp.length() == 5)); - } - - // take the string as is - { - auto str = std::string("hello"); - cstring_span<> sp = str; - CHECK((sp.length() == 5)); - } - - // ensure z on c strings - { - gsl::owner ptr = new char[3]; - - ptr[0] = 'a'; - ptr[1] = 'b'; - ptr[2] = '\0'; - - string_span<> span = ensure_z(ptr); - CHECK(span.length() == 2); - - delete[] ptr; - } + // comparison to string_span + CHECK(span == span); } - TEST(Constructors) { - // creating cstring_span + const char ar[] = {'H', 'e', 'l', 'l', 'o'}; + const char ar1[] = "Hello"; + const char ar2[10] = "Hello"; + const std::string str = "Hello"; + const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + const gsl::span sp = ensure_z("Hello"); - // from span of a final extent - { - span sp = "Hello"; - cstring_span<> span = sp; - CHECK(span.length() == 6); - } + cstring_span<> span = "Hello"; + + // const span, const other type + + CHECK(span == "Hello"); + CHECK(span == ar); + CHECK(span == ar1); + CHECK(span == ar2); +#ifdef CONFIRM_COMPILATION_ERRORS + const char* ptr = "Hello"; + CHECK(span == ptr); +#endif + CHECK(span == str); + CHECK(span == vec); + CHECK(span == sp); + + CHECK("Hello" == span); + CHECK(ar == span); + CHECK(ar1 == span); + CHECK(ar2 == span); +#ifdef CONFIRM_COMPILATION_ERRORS + CHECK(ptr == span); +#endif + CHECK(str == span); + CHECK(vec == span); + CHECK(sp == span); + + // const span, non-const other type + + char _ar[] = {'H', 'e', 'l', 'l', 'o'}; + char _ar1[] = "Hello"; + char _ar2[10] = "Hello"; + char* _ptr = _ar; + std::string _str = "Hello"; + std::vector _vec = {'H', 'e', 'l', 'l', 'o'}; + gsl::span _sp{_ar, 5}; + + CHECK(span == _ar); + CHECK(span == _ar1); + CHECK(span == _ar2); +#ifdef CONFIRM_COMPILATION_ERRORS + CHECK(span == _ptr); +#endif + CHECK(span == _str); + CHECK(span == _vec); + CHECK(span == _sp); + + CHECK(_ar == span); + CHECK(_ar1 == span); + CHECK(_ar2 == span); +#ifdef CONFIRM_COMPILATION_ERRORS + CHECK(_ptr == span); +#endif + CHECK(_str == span); + CHECK(_vec == span); + CHECK(_sp == span); + + string_span<> _span{_ptr, 5}; + + // non-const span, non-const other type + + CHECK(_span == _ar); + CHECK(_span == _ar1); + CHECK(_span == _ar2); +#ifdef CONFIRM_COMPILATION_ERRORS + CHECK(_span == _ptr); +#endif + CHECK(_span == _str); + CHECK(_span == _vec); + CHECK(_span == _sp); + + CHECK(_ar == _span); + CHECK(_ar1 == _span); + CHECK(_ar2 == _span); +#ifdef CONFIRM_COMPILATION_ERRORS + CHECK(_ptr == _span); +#endif + CHECK(_str == _span); + CHECK(_vec == _span); + CHECK(_sp == _span); + + // non-const span, const other type + + CHECK(_span == "Hello"); + CHECK(_span == ar); + CHECK(_span == ar1); + CHECK(_span == ar2); +#ifdef CONFIRM_COMPILATION_ERRORS + CHECK(_span == ptr); +#endif + CHECK(_span == str); + CHECK(_span == vec); + CHECK(_span == sp); + + CHECK("Hello" == _span); + CHECK(ar == _span); + CHECK(ar1 == _span); + CHECK(ar2 == _span); +#ifdef CONFIRM_COMPILATION_ERRORS + CHECK(ptr == _span); +#endif + CHECK(str == _span); + CHECK(vec == _span); + CHECK(sp == _span); + + // two spans + + CHECK(_span == span); + CHECK(span == _span); + } + + { + std::vector str1 = {'H', 'e', 'l', 'l', 'o'}; + cstring_span<> span1 = str1; + std::vector str2 = std::move(str1); + cstring_span<> span2 = str2; + + // comparison of spans from the same vector before and after move (ok) + CHECK(span1 == span2); + } +} + +TEST_CASE("ComparisonAndImplicitConstructors") +{ + { + cstring_span<> span = "Hello"; + + const char ar[] = {'H', 'e', 'l', 'l', 'o'}; + const char ar1[] = "Hello"; + const char ar2[10] = "Hello"; + const char* ptr = "Hello"; + const std::string str = "Hello"; + const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + + // comparison to literal + CHECK(span < cstring_span<>("Helloo")); + CHECK(span > cstring_span<>("Hell")); + + // comparison to static array with no null termination + CHECK(span >= cstring_span<>(ar)); + + // comparison to static array with null at the end + CHECK(span <= cstring_span<>(ar1)); + + // comparison to static array with null in the middle + CHECK(span >= cstring_span<>(ar2)); + + // comparison to null-terminated c string + CHECK(span <= cstring_span<>(ptr, 5)); + + // comparison to string + CHECK(span >= cstring_span<>(str)); + + // comparison to vector of charaters with no null termination + CHECK(span <= cstring_span<>(vec)); + } + + { + char ar[] = {'H', 'e', 'l', 'l', 'o'}; + + string_span<> span = ar; + + char larr[] = "Hell"; + char rarr[] = "Helloo"; + + char ar1[] = "Hello"; + char ar2[10] = "Hello"; + char* ptr = ar; + std::string str = "Hello"; + std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + + // comparison to static array with no null termination + CHECK(span <= string_span<>(ar)); + CHECK(span < string_span<>(rarr)); + CHECK(span > string_span<>(larr)); + + // comparison to static array with null at the end + CHECK(span >= string_span<>(ar1)); + + // comparison to static array with null in the middle + CHECK(span <= string_span<>(ar2)); + + // comparison to null-terminated c string + CHECK(span >= string_span<>(ptr, 5)); + + // comparison to string + CHECK(span <= string_span<>(str)); + + // comparison to vector of charaters with no null termination + CHECK(span >= string_span<>(vec)); + } +} +TEST_CASE("ConstrutorsEnsureZ") +{ + // remove z from literals + { + cstring_span<> sp = "hello"; + CHECK((sp.length() == 5)); + } + + // take the string as is + { + auto str = std::string("hello"); + cstring_span<> sp = str; + CHECK((sp.length() == 5)); + } + + // ensure z on c strings + { + gsl::owner ptr = new char[3]; + + ptr[0] = 'a'; + ptr[1] = 'b'; + ptr[2] = '\0'; + + string_span<> span = ensure_z(ptr); + CHECK(span.length() == 2); + + delete[] ptr; + } +} + +TEST_CASE("Constructors") +{ + // creating cstring_span + + // from span of a final extent + { + span sp = "Hello"; + cstring_span<> span = sp; + CHECK(span.length() == 6); + } // from const span of a final extent to non-const string_span #ifdef CONFIRM_COMPILATION_ERRORS - { - span sp = "Hello"; - string_span<> span = sp; - CHECK(span.length() == 6); - } + { + span sp = "Hello"; + string_span<> span = sp; + CHECK(span.length() == 6); + } #endif // from string temporary #ifdef CONFIRM_COMPILATION_ERRORS - { - cstring_span<> span = std::string("Hello"); - } + { + cstring_span<> span = std::string("Hello"); + } #endif - // default - { - cstring_span<> span; - CHECK(span.length() == 0); - } - - // from nullptr - { - cstring_span<> span(nullptr); - CHECK(span.length() == 0); - } - - // from string literal - { - cstring_span<> span = "Hello"; - CHECK(span.length() == 5); - } - - // from const static array - { - const char ar[] = {'H', 'e', 'l', 'l', 'o'}; - cstring_span<> span = ar; - CHECK(span.length() == 5); - } - - // from non-const static array - { - char ar[] = {'H', 'e', 'l', 'l', 'o'}; - cstring_span<> span = ar; - CHECK(span.length() == 5); - } - - // from const ptr and length - { - const char* ptr = "Hello"; - cstring_span<> span{ptr, 5}; - CHECK(span.length() == 5); - } - - // from const ptr and length, include 0 - { - const char* ptr = "Hello"; - cstring_span<> span{ptr, 6}; - CHECK(span.length() == 6); - } - - // from const ptr and length, 0 inside - { - const char* ptr = "He\0lo"; - cstring_span<> span{ptr, 5}; - CHECK(span.length() == 5); - } - - // from non-const ptr and length - { - char ar[] = {'H', 'e', 'l', 'l', 'o'}; - char* ptr = ar; - cstring_span<> span{ptr, 5}; - CHECK(span.length() == 5); - } - - // from non-const ptr and length, 0 inside - { - char ar[] = {'H', 'e', '\0', 'l', 'o'}; - char* ptr = ar; - cstring_span<> span{ptr, 5}; - CHECK(span.length() == 5); - } - - // from const string - { - const std::string str = "Hello"; - const cstring_span<> span = str; - CHECK(span.length() == 5); - } - - // from non-const string - { - std::string str = "Hello"; - const cstring_span<> span = str; - CHECK(span.length() == 5); - } - - // from const vector - { - const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - const cstring_span<> span = vec; - CHECK(span.length() == 5); - } - - // from non-const vector - { - std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - const cstring_span<> span = vec; - CHECK(span.length() == 5); - } - - // from const span - { - const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - const span inner = vec; - const cstring_span<> span = inner; - CHECK(span.length() == 5); - } - - // from non-const span - { - std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - const span inner = vec; - const cstring_span<> span = inner; - CHECK(span.length() == 5); - } - - // from const string_span - { - const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - const cstring_span<> tmp = vec; - const cstring_span<> span = tmp; - CHECK(span.length() == 5); - } - - // from non-const string_span - { - std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - string_span<> tmp = vec; - cstring_span<> span = tmp; - CHECK(span.length() == 5); - } - - // creating string_span - - // from string literal - { -#ifdef CONFIRM_COMPILATION_ERRORS - string_span<> span = "Hello"; -#endif - } - - // from const static array - { -#ifdef CONFIRM_COMPILATION_ERRORS - const char ar[] = {'H', 'e', 'l', 'l', 'o'}; - string_span<> span = ar; - CHECK(span.length() == 5); -#endif - } - - // from non-const static array - { - char ar[] = {'H', 'e', 'l', 'l', 'o'}; - string_span<> span = ar; - CHECK(span.length() == 5); - } - - // from const ptr and length - { -#ifdef CONFIRM_COMPILATION_ERRORS - const char* ptr = "Hello"; - string_span<> span{ptr, 5}; - CHECK(span.length() == 5); -#endif - } - - // from non-const ptr and length - { - char ar[] = {'H', 'e', 'l', 'l', 'o'}; - char* ptr = ar; - string_span<> span{ptr, 5}; - CHECK(span.length() == 5); - } - - // from const string - { -#ifdef CONFIRM_COMPILATION_ERRORS - const std::string str = "Hello"; - string_span<> span = str; - CHECK(span.length() == 5); -#endif - } - - // from non-const string - { - std::string str = "Hello"; - string_span<> span = str; - CHECK(span.length() == 5); - } - - // from const vector - { -#ifdef CONFIRM_COMPILATION_ERRORS - const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - string_span<> span = vec; - CHECK(span.length() == 5); -#endif - } - - // from non-const vector - { - std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - string_span<> span = vec; - CHECK(span.length() == 5); - } - - // from const span - { -#ifdef CONFIRM_COMPILATION_ERRORS - std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - const span inner = vec; - string_span<> span = inner; - CHECK(span.length() == 5); -#endif - } - - // from non-const span - { - std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - span inner = vec; - string_span<> span = inner; - CHECK(span.length() == 5); - } - - // from non-const span of non-const data from const vector - { -#ifdef CONFIRM_COMPILATION_ERRORS - const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - const span inner = vec; - string_span<> span = inner; - CHECK(span.length() == 5); -#endif - } - - // from const string_span - { -#ifdef CONFIRM_COMPILATION_ERRORS - std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - cstring_span<> tmp = vec; - string_span<> span = tmp; - CHECK(span.length() == 5); -#endif - } - - // from non-const string_span - { - std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - const string_span<> tmp = vec; - const string_span<> span = tmp; - CHECK(span.length() == 5); - } - - // from non-const string_span from const vector - { -#ifdef CONFIRM_COMPILATION_ERRORS - const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - string_span<> tmp = vec; - string_span<> span = tmp; - CHECK(span.length() == 5); -#endif - } - - // from const string_span of non-const data - { - std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - const string_span<> tmp = vec; - const string_span<> span = tmp; - CHECK(span.length() == 5); - } + // default + { + cstring_span<> span; + CHECK(span.length() == 0); } - template - T move_wrapper(T && t) + // from nullptr { - return std::move(t); + cstring_span<> span(nullptr); + CHECK(span.length() == 0); } - template - T create() + // from string literal { - return T{}; - } - - template - void use(basic_string_span) - { - } - - TEST(MoveConstructors) - { - // move string_span - { - cstring_span<> span = "Hello"; - const auto span1 = std::move(span); - CHECK(span1.length() == 5); - } - { - cstring_span<> span = "Hello"; - const auto span1 = move_wrapper(std::move(span)); - CHECK(span1.length() == 5); - } - { - cstring_span<> span = "Hello"; - const auto span1 = move_wrapper(std::move(span)); - CHECK(span1.length() == 5); - } - - // move span - { - span span = ensure_z("Hello"); - const cstring_span<> span1 = std::move(span); - CHECK(span1.length() == 5); - } - { - span span = ensure_z("Hello"); - const cstring_span<> span2 = move_wrapper(std::move(span)); - CHECK(span2.length() == 5); - } - - // move string - { -#ifdef CONFIRM_COMPILATION_ERRORS - std::string str = "Hello"; - string_span<> span = std::move(str); - CHECK(span.length() == 5); -#endif - } - { -#ifdef CONFIRM_COMPILATION_ERRORS - std::string str = "Hello"; - string_span<> span = move_wrapper(std::move(str)); - CHECK(span.length() == 5); -#endif - } - { -#ifdef CONFIRM_COMPILATION_ERRORS - use(create()); -#endif - } - - // move container - { -#ifdef CONFIRM_COMPILATION_ERRORS - std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - string_span<> span = std::move(vec); - CHECK(span.length() == 5); -#endif - } - { -#ifdef CONFIRM_COMPILATION_ERRORS - std::vector vec = {'H', 'e', 'l', 'l', 'o'}; - string_span<> span = move_wrapper>(std::move(vec)); - CHECK(span.length() == 5); -#endif - } - { -#ifdef CONFIRM_COMPILATION_ERRORS - use(create>()); -#endif - } - } - - TEST(Conversion) - { -#ifdef CONFIRM_COMPILATION_ERRORS cstring_span<> span = "Hello"; - cwstring_span<> wspan{span}; - CHECK(wspan.length() == 5); + CHECK(span.length() == 5); + } + + // from const static array + { + const char ar[] = {'H', 'e', 'l', 'l', 'o'}; + cstring_span<> span = ar; + CHECK(span.length() == 5); + } + + // from non-const static array + { + char ar[] = {'H', 'e', 'l', 'l', 'o'}; + cstring_span<> span = ar; + CHECK(span.length() == 5); + } + + // from const ptr and length + { + const char* ptr = "Hello"; + cstring_span<> span{ptr, 5}; + CHECK(span.length() == 5); + } + + // from const ptr and length, include 0 + { + const char* ptr = "Hello"; + cstring_span<> span{ptr, 6}; + CHECK(span.length() == 6); + } + + // from const ptr and length, 0 inside + { + const char* ptr = "He\0lo"; + cstring_span<> span{ptr, 5}; + CHECK(span.length() == 5); + } + + // from non-const ptr and length + { + char ar[] = {'H', 'e', 'l', 'l', 'o'}; + char* ptr = ar; + cstring_span<> span{ptr, 5}; + CHECK(span.length() == 5); + } + + // from non-const ptr and length, 0 inside + { + char ar[] = {'H', 'e', '\0', 'l', 'o'}; + char* ptr = ar; + cstring_span<> span{ptr, 5}; + CHECK(span.length() == 5); + } + + // from const string + { + const std::string str = "Hello"; + const cstring_span<> span = str; + CHECK(span.length() == 5); + } + + // from non-const string + { + std::string str = "Hello"; + const cstring_span<> span = str; + CHECK(span.length() == 5); + } + + // from const vector + { + const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + const cstring_span<> span = vec; + CHECK(span.length() == 5); + } + + // from non-const vector + { + std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + const cstring_span<> span = vec; + CHECK(span.length() == 5); + } + + // from const span + { + const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + const span inner = vec; + const cstring_span<> span = inner; + CHECK(span.length() == 5); + } + + // from non-const span + { + std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + const span inner = vec; + const cstring_span<> span = inner; + CHECK(span.length() == 5); + } + + // from const string_span + { + const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + const cstring_span<> tmp = vec; + const cstring_span<> span = tmp; + CHECK(span.length() == 5); + } + + // from non-const string_span + { + std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + string_span<> tmp = vec; + cstring_span<> span = tmp; + CHECK(span.length() == 5); + } + + // creating string_span + + // from string literal + { +#ifdef CONFIRM_COMPILATION_ERRORS + string_span<> span = "Hello"; #endif } - czstring_span<> CreateTempName(string_span<> span) + // from const static array { - Expects(span.size() > 1); - - int last = 0; - if (span.size() > 4) { - span[0] = 't'; - span[1] = 'm'; - span[2] = 'p'; - last = 3; - } - span[last] = '\0'; - - auto ret = span.subspan(0, 4); - return {ret}; +#ifdef CONFIRM_COMPILATION_ERRORS + const char ar[] = {'H', 'e', 'l', 'l', 'o'}; + string_span<> span = ar; + CHECK(span.length() == 5); +#endif } - TEST(zstring) + // from non-const static array { - - // create zspan from zero terminated string - { - char buf[1]; - buf[0] = '\0'; - - zstring_span<> zspan({buf, 1}); - - CHECK(strlen(zspan.assume_z()) == 0); - CHECK(zspan.as_string_span().size() == 0); - CHECK(zspan.ensure_z().size() == 0); - } - - // create zspan from non-zero terminated string - { - char buf[1]; - buf[0] = 'a'; - - auto workaround_macro = [&]() { zstring_span<> zspan({buf, 1}); }; - CHECK_THROW(workaround_macro(), fail_fast); - } - - // usage scenario: create zero-terminated temp file name and pass to a legacy API - { - char buf[10]; - - auto name = CreateTempName({buf, 10}); - if (!name.empty()) { - czstring<> str = name.assume_z(); - CHECK(strlen(str) == 3); - CHECK(*(str + 3) == '\0'); - } - } + char ar[] = {'H', 'e', 'l', 'l', 'o'}; + string_span<> span = ar; + CHECK(span.length() == 5); } - cwzstring_span<> CreateTempNameW(wstring_span<> span) + // from const ptr and length { - Expects(span.size() > 1); - - int last = 0; - if (span.size() > 4) { - span[0] = L't'; - span[1] = L'm'; - span[2] = L'p'; - last = 3; - } - span[last] = L'\0'; - - auto ret = span.subspan(0, 4); - return {ret}; +#ifdef CONFIRM_COMPILATION_ERRORS + const char* ptr = "Hello"; + string_span<> span{ptr, 5}; + CHECK(span.length() == 5); +#endif } - TEST(wzstring) + // from non-const ptr and length { - - // create zspan from zero terminated string - { - wchar_t buf[1]; - buf[0] = L'\0'; - - wzstring_span<> zspan({buf, 1}); - - CHECK(wcsnlen(zspan.assume_z(), 1) == 0); - CHECK(zspan.as_string_span().size() == 0); - CHECK(zspan.ensure_z().size() == 0); - } - - // create zspan from non-zero terminated string - { - wchar_t buf[1]; - buf[0] = L'a'; - - const auto workaround_macro = [&]() { wzstring_span<> zspan({buf, 1}); }; - CHECK_THROW(workaround_macro(), fail_fast); - } - - // usage scenario: create zero-terminated temp file name and pass to a legacy API - { - wchar_t buf[10]; - - const auto name = CreateTempNameW({buf, 10}); - if (!name.empty()) { - cwzstring<> str = name.assume_z(); - CHECK(wcsnlen(str, 10) == 3); - CHECK(*(str + 3) == L'\0'); - } - } + char ar[] = {'H', 'e', 'l', 'l', 'o'}; + char* ptr = ar; + string_span<> span{ptr, 5}; + CHECK(span.length() == 5); } - TEST(Issue305) + // from const string { - std::map, int> foo = {{"foo", 0}, {"bar", 1}}; - CHECK(foo["foo"] == 0); - CHECK(foo["bar"] == 1); +#ifdef CONFIRM_COMPILATION_ERRORS + const std::string str = "Hello"; + string_span<> span = str; + CHECK(span.length() == 5); +#endif + } + + // from non-const string + { + std::string str = "Hello"; + string_span<> span = str; + CHECK(span.length() == 5); + } + + // from const vector + { +#ifdef CONFIRM_COMPILATION_ERRORS + const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + string_span<> span = vec; + CHECK(span.length() == 5); +#endif + } + + // from non-const vector + { + std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + string_span<> span = vec; + CHECK(span.length() == 5); + } + + // from const span + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + const span inner = vec; + string_span<> span = inner; + CHECK(span.length() == 5); +#endif + } + + // from non-const span + { + std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + span inner = vec; + string_span<> span = inner; + CHECK(span.length() == 5); + } + + // from non-const span of non-const data from const vector + { +#ifdef CONFIRM_COMPILATION_ERRORS + const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + const span inner = vec; + string_span<> span = inner; + CHECK(span.length() == 5); +#endif + } + + // from const string_span + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + cstring_span<> tmp = vec; + string_span<> span = tmp; + CHECK(span.length() == 5); +#endif + } + + // from non-const string_span + { + std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + const string_span<> tmp = vec; + const string_span<> span = tmp; + CHECK(span.length() == 5); + } + + // from non-const string_span from const vector + { +#ifdef CONFIRM_COMPILATION_ERRORS + const std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + string_span<> tmp = vec; + string_span<> span = tmp; + CHECK(span.length() == 5); +#endif + } + + // from const string_span of non-const data + { + std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + const string_span<> tmp = vec; + const string_span<> span = tmp; + CHECK(span.length() == 5); } } -int main(int, const char* []) { return UnitTest::RunAllTests(); } +template +T move_wrapper(T && t) +{ + return std::move(t); +} + +template +T create() +{ + return T{}; +} + +template +void use(basic_string_span) +{ +} + +TEST_CASE("MoveConstructors") +{ + // move string_span + { + cstring_span<> span = "Hello"; + const auto span1 = std::move(span); + CHECK(span1.length() == 5); + } + { + cstring_span<> span = "Hello"; + const auto span1 = move_wrapper(std::move(span)); + CHECK(span1.length() == 5); + } + { + cstring_span<> span = "Hello"; + const auto span1 = move_wrapper(std::move(span)); + CHECK(span1.length() == 5); + } + + // move span + { + span span = ensure_z("Hello"); + const cstring_span<> span1 = std::move(span); + CHECK(span1.length() == 5); + } + { + span span = ensure_z("Hello"); + const cstring_span<> span2 = move_wrapper(std::move(span)); + CHECK(span2.length() == 5); + } + + // move string + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::string str = "Hello"; + string_span<> span = std::move(str); + CHECK(span.length() == 5); +#endif + } + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::string str = "Hello"; + string_span<> span = move_wrapper(std::move(str)); + CHECK(span.length() == 5); +#endif + } + { +#ifdef CONFIRM_COMPILATION_ERRORS + use(create()); +#endif + } + + // move container + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + string_span<> span = std::move(vec); + CHECK(span.length() == 5); +#endif + } + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::vector vec = {'H', 'e', 'l', 'l', 'o'}; + string_span<> span = move_wrapper>(std::move(vec)); + CHECK(span.length() == 5); +#endif + } + { +#ifdef CONFIRM_COMPILATION_ERRORS + use(create>()); +#endif + } +} + +TEST_CASE("Conversion") +{ +#ifdef CONFIRM_COMPILATION_ERRORS + cstring_span<> span = "Hello"; + cwstring_span<> wspan{span}; + CHECK(wspan.length() == 5); +#endif +} + +czstring_span<> CreateTempName(string_span<> span) +{ + Expects(span.size() > 1); + + int last = 0; + if (span.size() > 4) { + span[0] = 't'; + span[1] = 'm'; + span[2] = 'p'; + last = 3; + } + span[last] = '\0'; + + auto ret = span.subspan(0, 4); + return {ret}; +} + +TEST_CASE("zstring") +{ + + // create zspan from zero terminated string + { + char buf[1]; + buf[0] = '\0'; + + zstring_span<> zspan({buf, 1}); + + CHECK(strlen(zspan.assume_z()) == 0); + CHECK(zspan.as_string_span().size() == 0); + CHECK(zspan.ensure_z().size() == 0); + } + + // create zspan from non-zero terminated string + { + char buf[1]; + buf[0] = 'a'; + + auto workaround_macro = [&]() { zstring_span<> zspan({buf, 1}); }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } + + // usage scenario: create zero-terminated temp file name and pass to a legacy API + { + char buf[10]; + + auto name = CreateTempName({buf, 10}); + if (!name.empty()) { + czstring<> str = name.assume_z(); + CHECK(strlen(str) == 3); + CHECK(*(str + 3) == '\0'); + } + } +} + +cwzstring_span<> CreateTempNameW(wstring_span<> span) +{ + Expects(span.size() > 1); + + int last = 0; + if (span.size() > 4) { + span[0] = L't'; + span[1] = L'm'; + span[2] = L'p'; + last = 3; + } + span[last] = L'\0'; + + auto ret = span.subspan(0, 4); + return {ret}; +} + +TEST_CASE("wzstring") +{ + + // create zspan from zero terminated string + { + wchar_t buf[1]; + buf[0] = L'\0'; + + wzstring_span<> zspan({buf, 1}); + + CHECK(wcsnlen(zspan.assume_z(), 1) == 0); + CHECK(zspan.as_string_span().size() == 0); + CHECK(zspan.ensure_z().size() == 0); + } + + // create zspan from non-zero terminated string + { + wchar_t buf[1]; + buf[0] = L'a'; + + const auto workaround_macro = [&]() { wzstring_span<> zspan({buf, 1}); }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } + + // usage scenario: create zero-terminated temp file name and pass to a legacy API + { + wchar_t buf[10]; + + const auto name = CreateTempNameW({buf, 10}); + if (!name.empty()) { + cwzstring<> str = name.assume_z(); + CHECK(wcsnlen(str, 10) == 3); + CHECK(*(str + 3) == L'\0'); + } + } +} + +TEST_CASE("Issue305") +{ + std::map, int> foo = {{"foo", 0}, {"bar", 1}}; + CHECK(foo["foo"] == 0); + CHECK(foo["bar"] == 1); +} diff --git a/tests/test.cpp b/tests/test.cpp new file mode 100644 index 0000000..bae194d --- /dev/null +++ b/tests/test.cpp @@ -0,0 +1,18 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#define CATCH_CONFIG_MAIN +#include diff --git a/tests/unittest-cpp b/tests/unittest-cpp deleted file mode 160000 index c331bb0..0000000 --- a/tests/unittest-cpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c331bb0deaaf92659a31887c029ee34cac2ab19e diff --git a/tests/utils_tests.cpp b/tests/utils_tests.cpp index d45af3c..67cceb5 100644 --- a/tests/utils_tests.cpp +++ b/tests/utils_tests.cpp @@ -14,7 +14,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include @@ -22,94 +22,89 @@ using namespace gsl; -SUITE(utils_tests) +void f(int& i) { i += 1; } + +TEST_CASE("finally_lambda") { - void f(int& i) { i += 1; } - - TEST(finally_lambda) + int i = 0; { - int i = 0; - { - auto _ = finally([&]() { f(i); }); - CHECK(i == 0); - } - CHECK(i == 1); - } - - TEST(finally_lambda_move) - { - int i = 0; - { - auto _1 = finally([&]() { f(i); }); - { - auto _2 = std::move(_1); - CHECK(i == 0); - } - CHECK(i == 1); - { - auto _2 = std::move(_1); - CHECK(i == 1); - } - CHECK(i == 1); - } - CHECK(i == 1); - } - - TEST(finally_function_with_bind) - { - int i = 0; - { - auto _ = finally(std::bind(&f, std::ref(i))); - CHECK(i == 0); - } - CHECK(i == 1); - } - - int j = 0; - void g() { j += 1; } - TEST(finally_function_ptr) - { - j = 0; - { - auto _ = finally(&g); - CHECK(j == 0); - } - CHECK(j == 1); - } - - TEST(narrow_cast) - { - int n = 120; - char c = narrow_cast(n); - CHECK(c == 120); - - n = 300; - unsigned char uc = narrow_cast(n); - CHECK(uc == 44); - } - - TEST(narrow) - { - int n = 120; - const char c = narrow(n); - CHECK(c == 120); - - n = 300; - CHECK_THROW(narrow(n), narrowing_error); - - const auto int32_max = std::numeric_limits::max(); - const auto int32_min = std::numeric_limits::min(); - - CHECK(narrow(int32_t(0)) == 0); - CHECK(narrow(int32_t(1)) == 1); - CHECK(narrow(int32_max) == static_cast(int32_max)); - - CHECK_THROW(narrow(int32_t(-1)), narrowing_error); - CHECK_THROW(narrow(int32_min), narrowing_error); - - n = -42; - CHECK_THROW(narrow(n), narrowing_error); + auto _ = finally([&]() { f(i); }); + CHECK(i == 0); } + CHECK(i == 1); } -int main(int, const char* []) { return UnitTest::RunAllTests(); } +TEST_CASE("finally_lambda_move") +{ + int i = 0; + { + auto _1 = finally([&]() { f(i); }); + { + auto _2 = std::move(_1); + CHECK(i == 0); + } + CHECK(i == 1); + { + auto _2 = std::move(_1); + CHECK(i == 1); + } + CHECK(i == 1); + } + CHECK(i == 1); +} + +TEST_CASE("finally_function_with_bind") +{ + int i = 0; + { + auto _ = finally(std::bind(&f, std::ref(i))); + CHECK(i == 0); + } + CHECK(i == 1); +} + +int j = 0; +void g() { j += 1; } +TEST_CASE("finally_function_ptr") +{ + j = 0; + { + auto _ = finally(&g); + CHECK(j == 0); + } + CHECK(j == 1); +} + +TEST_CASE("narrow_cast") +{ + int n = 120; + char c = narrow_cast(n); + CHECK(c == 120); + + n = 300; + unsigned char uc = narrow_cast(n); + CHECK(uc == 44); +} + +TEST_CASE("narrow") +{ + int n = 120; + const char c = narrow(n); + CHECK(c == 120); + + n = 300; + CHECK_THROWS_AS(narrow(n), narrowing_error); + + const auto int32_max = std::numeric_limits::max(); + const auto int32_min = std::numeric_limits::min(); + + CHECK(narrow(int32_t(0)) == 0); + CHECK(narrow(int32_t(1)) == 1); + CHECK(narrow(int32_max) == static_cast(int32_max)); + + CHECK_THROWS_AS(narrow(int32_t(-1)), narrowing_error); + CHECK_THROWS_AS(narrow(int32_min), narrowing_error); + + n = -42; + CHECK_THROWS_AS(narrow(n), narrowing_error); +}