From b2ee48433448556a7be63074f8aaf45ab47a95c1 Mon Sep 17 00:00:00 2001 From: Neil MacIntosh Date: Thu, 13 Jul 2017 13:53:56 -0700 Subject: [PATCH] Move from unittest-cpp to catch for unit testing. (#533) Many thanks to @rianquinn. This should fix #495, #494 and #529. --- .gitignore | 2 + .gitmodules | 3 - .travis.yml | 17 +- CMakeLists.txt | 11 +- README.md | 11 +- ThirdPartyNotices.txt | 39 + appveyor.yml | 11 +- include/gsl/multi_span | 1 + include/gsl/span | 1 + tests/CMakeLists.txt | 41 +- tests/algorithm_tests.cpp | 312 +++-- tests/assertion_tests.cpp | 49 +- tests/at_tests.cpp | 99 +- tests/bounds_tests.cpp | 127 +- tests/byte_tests.cpp | 178 ++- tests/multi_span_tests.cpp | 2521 +++++++++++++++++----------------- tests/notnull_tests.cpp | 354 +++-- tests/owner_tests.cpp | 41 +- tests/span_tests.cpp | 1530 +++++++++++---------- tests/strided_span_tests.cpp | 1365 +++++++++--------- tests/string_span_tests.cpp | 1706 ++++++++++++----------- tests/test.cpp | 18 + tests/unittest-cpp | 1 - tests/utils_tests.cpp | 169 ++- 24 files changed, 4315 insertions(+), 4292 deletions(-) delete mode 100644 .gitmodules create mode 100644 ThirdPartyNotices.txt create mode 100644 tests/test.cpp delete mode 160000 tests/unittest-cpp 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..e62a1d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,16 @@ -cmake_minimum_required(VERSION 2.8.7) +cmake_minimum_required(VERSION 3.1.3) 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 9b7ae92..3b830c5 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,9 @@ other platforms. Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for more inform # Project Code of Conduct This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. +# Usage of Third Party Libraries +This project makes use of the [Catch](https://github.com/philsquared/catch) testing library. Please see the [ThirdPartyNotices.txt](./ThirdPartyNotices.txt) file for details regarding the licensing of Catch. + # Quick Start ## Supported Platforms The test suite that exercises GSL has been built and passes successfully on the following platforms:1) @@ -40,9 +43,7 @@ contributing any changes that were necessary back to this project to benefit the ## Building the tests 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. +* [CMake](http://cmake.org), version 3.1.3 or later to be installed and in your PATH. These steps assume the source code of this repository has been cloned into a directory named `c:\GSL`. @@ -56,11 +57,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/ThirdPartyNotices.txt b/ThirdPartyNotices.txt new file mode 100644 index 0000000..94b9acc --- /dev/null +++ b/ThirdPartyNotices.txt @@ -0,0 +1,39 @@ + +THIRD-PARTY SOFTWARE NOTICES AND INFORMATION +Do Not Translate or Localize + +GSL: Guideline Support Library incorporates third party material from the projects listed below. The original copyright notice and the license under which Microsoft received such third party material are set forth below. Microsoft reserves all other rights not expressly granted, whether by implication, estoppel or otherwise. + + +1. Catch (https://github.com/philsquared/Catch) + + +%% Catch NOTICES, INFORMATION, AND LICENSE BEGIN HERE +========================================= +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +========================================= +END OF Catch NOTICES, INFORMATION, AND LICENSE + + 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 e381861..618c95e 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 0d8841b..f3a76b1 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..5306e85 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.6 + 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 caab476..62f1e57 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -14,7 +14,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include @@ -104,192 +104,182 @@ struct NonCopyableNonMovable NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete; }; +bool helper(not_null p) { return *p == 12; } -SUITE(NotNullTests) +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)); - } - - TEST(TestNotNullDereferenceOperator) - { - { - auto sp1 = std::make_shared(); - - using NotNullSp1 = not_null; - CHECK(typeid(*sp1) == typeid(*NotNullSp1(sp1))); - CHECK(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1)); - } - - { - int ints[1] = { 42 }; - CustomPtr p1(&ints[0]); - - using NotNull1 = not_null; - CHECK(typeid(*NotNull1(p1)) == typeid(*p1)); - CHECK(*NotNull1(p1) == 42); - *NotNull1(p1) = 43; - CHECK(ints[0] == 43); - } - - { - int v = 42; - gsl::not_null p(&v); - CHECK(typeid(*p) == typeid(*(&v))); - *p = 43; - CHECK(v == 43); - } - } + 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)); + +} + +TEST_CASE("TestNotNullDereferenceOperator") +{ + { + auto sp1 = std::make_shared(); + + using NotNullSp1 = not_null; + CHECK(typeid(*sp1) == typeid(*NotNullSp1(sp1))); + CHECK(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1)); + } + + { + int ints[1] = { 42 }; + CustomPtr p1(&ints[0]); + + using NotNull1 = not_null; + CHECK(typeid(*NotNull1(p1)) == typeid(*p1)); + CHECK(*NotNull1(p1) == 42); + *NotNull1(p1) = 43; + CHECK(ints[0] == 43); + } + + { + int v = 42; + gsl::not_null p(&v); + CHECK(typeid(*p) == typeid(*(&v))); + *p = 43; + CHECK(v == 43); + } +} + +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 459c646..9885a68 100644 --- a/tests/owner_tests.cpp +++ b/tests/owner_tests.cpp @@ -14,7 +14,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include #include @@ -24,28 +24,23 @@ 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; - } - - TEST(check_pointer_constraint) - { - #ifdef CONFIRM_COMPILATION_ERRORS - { - owner integerTest = 10; - owner> sharedPtrTest(new int(10)); - } - #endif - } + owner p = new int(120); + CHECK(*p == 120); + f(p); + CHECK(*p == 121); + delete p; } -int main(int, const char* []) { return UnitTest::RunAllTests(); } +TEST_CASE("check_pointer_constraint") +{ + #ifdef CONFIRM_COMPILATION_ERRORS + { + owner integerTest = 10; + owner> sharedPtrTest(new int(10)); + } + #endif +} 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); +}