├── .clang-format ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE_1_0.txt ├── README.md ├── appveyor.yml ├── include └── tcb │ └── span.hpp └── test ├── CMakeLists.txt ├── catch.hpp ├── catch_main.cpp ├── test_contract_checking.cpp ├── test_deduction_guides.cpp ├── test_span.cpp └── test_structured_bindings.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | 2 | ColumnLimit: 80 3 | 4 | UseTab: Never 5 | IndentWidth: 4 6 | AccessModifierOffset: -4 7 | 8 | AlignConsecutiveAssignments: false 9 | AllowShortFunctionsOnASingleLine: Inline 10 | AlwaysBreakTemplateDeclarations: true 11 | BreakBeforeBraces: Custom 12 | BreakConstructorInitializers: BeforeColon 13 | BraceWrapping: 14 | AfterFunction: true 15 | SplitEmptyFunction: false 16 | SplitEmptyRecord: false 17 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 18 | Cpp11BracedListStyle: true 19 | DerivePointerAlignment: true 20 | NamespaceIndentation: None 21 | FixNamespaceComments: true 22 | SpaceAfterCStyleCast: true 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Common CMake build directories 3 | build*/ 4 | 5 | # QtCreator 6 | CMakeLists.txt.user 7 | 8 | # CLion 9 | .idea/ 10 | cmake-build*/ 11 | 12 | # VS Code 13 | .vscode/ 14 | 15 | # Visual Studio 16 | .vs/ 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Travis CI config file 3 | # 4 | # Copyright Tristan Brindle 2019 5 | # 6 | # Use, modification and distribution is subject to the 7 | # Boost Software License, Version 1.0. (See accompanying 8 | # file LICENSE_1_0.txt or copy at 9 | # http://www.boost.org/LICENSE_1_0.txt) 10 | # 11 | # Heavily based on travis.yml from Boost.Hana 12 | # 13 | # Copyright Louis Dionne 2013-18 14 | # 15 | 16 | language: cpp 17 | 18 | os: linux 19 | dist: xenial 20 | sudo: false 21 | 22 | # Do not build branches of the form "pr/*". By prefixing pull requests coming 23 | # from branches inside the repository with pr/, this avoids building both the 24 | # branch push _and_ the pull request. 25 | # Based on https://github.com/boostorg/hana/blob/master/.travis.yml 26 | branches: 27 | except: /pr\/.*/ 28 | 29 | matrix: 30 | include: 31 | # 32 | # Mac OS builds 33 | # 34 | - os: osx 35 | osx_image: xcode11 36 | env: COMPILER=clang++ CPP_VER=17 37 | 38 | - os: osx 39 | osx_image: xcode11 40 | env: COMPILER=clang++ CPP_VER=14 41 | 42 | - os: osx 43 | osx_image: xcode11 44 | env: COMPILER=clang++ CPP_VER=11 45 | 46 | - os: osx 47 | osx_image: xcode10.2 48 | env: COMPILER=clang++ CPP_VER=17 49 | 50 | - os: osx 51 | osx_image: xcode10.2 52 | env: COMPILER=clang++ CPP_VER=14 53 | 54 | - os: osx 55 | osx_image: xcode10.2 56 | env: COMPILER=clang++ CPP_VER=11 57 | 58 | - os: osx 59 | osx_image: xcode10.1 60 | env: COMPILER=clang++ CPP_VER=17 61 | 62 | - os: osx 63 | osx_image: xcode10.1 64 | env: COMPILER=clang++ CPP_VER=14 65 | 66 | - os: osx 67 | osx_image: xcode10.1 68 | env: COMPILER=clang++ CPP_VER=11 69 | 70 | - os: osx 71 | osx_image: xcode10 72 | env: COMPILER=clang++ CPP_VER=17 73 | 74 | - os: osx 75 | osx_image: xcode10 76 | env: COMPILER=clang++ CPP_VER=14 77 | 78 | - os: osx 79 | osx_image: xcode10 80 | env: COMPILER=clang++ CPP_VER=11 81 | 82 | - os: osx 83 | osx_image: xcode9.4 84 | env: COMPILER=clang++ CPP_VER=14 85 | 86 | - os: osx 87 | osx_image: xcode9.4 88 | env: COMPILER=clang++ CPP_VER=11 89 | 90 | - os: osx 91 | osx_image: xcode9.3 92 | env: COMPILER=clang++ CPP_VER=14 93 | 94 | - os: osx 95 | osx_image: xcode9.3 96 | env: COMPILER=clang++ CPP_VER=11 97 | 98 | - os: osx 99 | osx_image: xcode9.2 100 | env: COMPILER=clang++ CPP_VER=14 101 | 102 | - os: osx 103 | osx_image: xcode9.2 104 | env: COMPILER=clang++ CPP_VER=11 105 | 106 | - os: osx 107 | osx_image: xcode9.1 108 | env: COMPILER=clang++ CPP_VER=14 109 | 110 | - os: osx 111 | osx_image: xcode9.1 112 | env: COMPILER=clang++ CPP_VER=11 113 | 114 | - os: osx 115 | osx_image: xcode9 116 | env: COMPILER=clang++ CPP_VER=14 117 | 118 | - os: osx 119 | osx_image: xcode9 120 | env: COMPILER=clang++ CPP_VER=11 121 | 122 | - os: osx 123 | osx_image: xcode8.3 124 | env: COMPILER=clang++ CPP_VER=14 125 | 126 | - os: osx 127 | osx_image: xcode8.3 128 | env: COMPILER=clang++ CPP_VER=11 129 | 130 | # 131 | # Linux builds 132 | # 133 | # GCC 9, C++17 134 | - env: COMPILER=g++-9 CPP_VER=17 135 | addons: 136 | apt: 137 | packages: 138 | - g++-9 139 | sources: 140 | - ubuntu-toolchain-r-test 141 | 142 | # GCC9, C++14 143 | - env: COMPILER=g++-9 CPP_VER=14 144 | addons: 145 | apt: 146 | packages: 147 | - g++-9 148 | sources: 149 | - ubuntu-toolchain-r-test 150 | 151 | # GCC9, C++11 152 | - env: COMPILER=g++-9 CPP_VER=11 153 | addons: 154 | apt: 155 | packages: 156 | - g++-9 157 | sources: 158 | - ubuntu-toolchain-r-test 159 | 160 | # GCC 8, C++17 161 | - env: COMPILER=g++-8 CPP_VER=17 162 | addons: 163 | apt: 164 | packages: 165 | - g++-8 166 | sources: 167 | - ubuntu-toolchain-r-test 168 | 169 | # GCC8, C++14 170 | - env: COMPILER=g++-8 CPP_VER=14 171 | addons: 172 | apt: 173 | packages: 174 | - g++-8 175 | sources: 176 | - ubuntu-toolchain-r-test 177 | 178 | # GCC8, C++11 179 | - env: COMPILER=g++-8 CPP_VER=11 180 | addons: 181 | apt: 182 | packages: 183 | - g++-8 184 | sources: 185 | - ubuntu-toolchain-r-test 186 | 187 | # GCC 7, C++17 188 | - env: COMPILER=g++-7 CPP_VER=17 189 | addons: 190 | apt: 191 | packages: 192 | - g++-7 193 | sources: 194 | - ubuntu-toolchain-r-test 195 | 196 | # GCC7, C++14 197 | - env: COMPILER=g++-7 CPP_VER=14 198 | addons: 199 | apt: 200 | packages: 201 | - g++-7 202 | sources: 203 | - ubuntu-toolchain-r-test 204 | 205 | # GCC7, C++11 206 | - env: COMPILER=g++-7 CPP_VER=11 207 | addons: 208 | apt: 209 | packages: 210 | - g++-7 211 | sources: 212 | - ubuntu-toolchain-r-test 213 | 214 | # GCC 6, C++14 215 | - env: COMPILER=g++-6 CPP_VER=14 216 | addons: 217 | apt: 218 | packages: 219 | - g++-6 220 | sources: 221 | - ubuntu-toolchain-r-test 222 | 223 | # GCC 6, C++11 224 | - env: COMPILER=g++-6 CPP_VER=11 225 | addons: 226 | apt: 227 | packages: 228 | - g++-6 229 | sources: 230 | - ubuntu-toolchain-r-test 231 | 232 | # GCC 5, C++14 233 | - env: COMPILER=g++-5 CPP_VER=14 234 | addons: 235 | apt: 236 | packages: 237 | - g++-5 238 | sources: 239 | - ubuntu-toolchain-r-test 240 | 241 | # GCC 5, C++11 242 | - env: COMPILER=g++-5 CPP_VER=11 243 | addons: 244 | apt: 245 | packages: 246 | - g++-5 247 | sources: 248 | - ubuntu-toolchain-r-test 249 | 250 | # Clang 8, C++17 251 | - env: COMPILER=clang++-8 CPP_VER=17 252 | addons: 253 | apt: 254 | packages: 255 | - clang-8 256 | sources: 257 | - ubuntu-toolchain-r-test 258 | - llvm-toolchain-xenial-8 259 | 260 | # Clang 8, C++14 261 | - env: COMPILER=clang++-8 CPP_VER=14 262 | addons: 263 | apt: 264 | packages: 265 | - clang-8 266 | sources: 267 | - ubuntu-toolchain-r-test 268 | - llvm-toolchain-xenial-8 269 | 270 | # Clang 8, C++11 271 | - env: COMPILER=clang++-8 CPP_VER=11 272 | addons: 273 | apt: 274 | packages: 275 | - clang-8 276 | sources: 277 | - ubuntu-toolchain-r-test 278 | - llvm-toolchain-xenial-8 279 | 280 | # Clang 7, C++17 281 | - env: COMPILER=clang++-7 CPP_VER=17 282 | addons: 283 | apt: 284 | packages: 285 | - clang-7 286 | sources: 287 | - ubuntu-toolchain-r-test 288 | - llvm-toolchain-xenial-7 289 | 290 | # Clang 7, C++14 291 | - env: COMPILER=clang++-7 CPP_VER=14 292 | addons: 293 | apt: 294 | packages: 295 | - clang-7 296 | sources: 297 | - ubuntu-toolchain-r-test 298 | - llvm-toolchain-xenial-7 299 | 300 | # Clang 7, C++11 301 | - env: COMPILER=clang++-7 CPP_VER=11 302 | addons: 303 | apt: 304 | packages: 305 | - clang-7 306 | sources: 307 | - ubuntu-toolchain-r-test 308 | - llvm-toolchain-xenial-7 309 | 310 | # Clang 6, C++17 311 | - env: COMPILER=clang++-6.0 CPP_VER=17 312 | addons: 313 | apt: 314 | packages: 315 | - clang-6.0 316 | sources: 317 | - ubuntu-toolchain-r-test 318 | - llvm-toolchain-xenial-6.0 319 | 320 | # Clang 6, C++14 321 | - env: COMPILER=clang++-6.0 CPP_VER=14 322 | addons: 323 | apt: 324 | packages: 325 | - clang-6.0 326 | sources: 327 | - ubuntu-toolchain-r-test 328 | - llvm-toolchain-xenial-6.0 329 | 330 | # Clang 6, C++11 331 | - env: COMPILER=clang++-6.0 CPP_VER=11 332 | addons: 333 | apt: 334 | packages: 335 | - clang-6.0 336 | sources: 337 | - ubuntu-toolchain-r-test 338 | - llvm-toolchain-xenial-6.0 339 | 340 | # Clang 5, C++17 341 | - env: COMPILER=clang++-5.0 CPP_VER=17 342 | addons: 343 | apt: 344 | packages: 345 | - clang-5.0 346 | sources: 347 | - ubuntu-toolchain-r-test 348 | - llvm-toolchain-xenial-5.0 349 | 350 | # Clang 5, C++14 351 | - env: COMPILER=clang++-5.0 CPP_VER=14 352 | addons: 353 | apt: 354 | packages: 355 | - clang-5.0 356 | sources: 357 | - ubuntu-toolchain-r-test 358 | - llvm-toolchain-xenial-5.0 359 | 360 | # Clang 5, C++11 361 | - env: COMPILER=clang++-5.0 CPP_VER=11 362 | addons: 363 | apt: 364 | packages: 365 | - clang-5.0 366 | sources: 367 | - ubuntu-toolchain-r-test 368 | - llvm-toolchain-xenial-5.0 369 | 370 | # Clang 4, C++17 371 | - env: COMPILER=clang++-4.0 CPP_VER=17 372 | addons: 373 | apt: 374 | packages: 375 | - clang-4.0 376 | sources: 377 | - ubuntu-toolchain-r-test 378 | - llvm-toolchain-xenial-4.0 379 | 380 | # Clang 4, C++14 381 | - env: COMPILER=clang++-4.0 CPP_VER=14 382 | addons: 383 | apt: 384 | packages: 385 | - clang-4.0 386 | sources: 387 | - ubuntu-toolchain-r-test 388 | - llvm-toolchain-xenial-4.0 389 | 390 | # Clang 4, C++11 391 | - env: COMPILER=clang++-4.0 CPP_VER=11 392 | addons: 393 | apt: 394 | packages: 395 | - clang-4.0 396 | sources: 397 | - ubuntu-toolchain-r-test 398 | - llvm-toolchain-xenial-4.0 399 | 400 | # Clang 3.9, C++14 401 | - env: COMPILER=clang++-3.9 CPP_VER=14 402 | addons: 403 | apt: 404 | packages: 405 | - clang-3.9 406 | sources: 407 | - ubuntu-toolchain-r-test 408 | - llvm-toolchain-xenial-3.9 409 | 410 | # Clang 3.9, C++11 411 | - env: COMPILER=clang++-3.9 CPP_VER=11 412 | addons: 413 | apt: 414 | packages: 415 | - clang-3.9 416 | sources: 417 | - ubuntu-toolchain-r-test 418 | - llvm-toolchain-xenial-3.9 419 | 420 | # Clang 3.8, C++14 421 | - env: COMPILER=clang++-3.8 CPP_VER=14 422 | addons: 423 | apt: 424 | packages: 425 | - clang-3.8 426 | sources: 427 | - ubuntu-toolchain-r-test 428 | - llvm-toolchain-xenial-3.8 429 | 430 | # Clang 3.8, C++11 431 | - env: COMPILER=clang++-3.8 CPP_VER=11 432 | addons: 433 | apt: 434 | packages: 435 | - clang-3.8 436 | sources: 437 | - ubuntu-toolchain-r-test 438 | - llvm-toolchain-xenial-3.8 439 | 440 | # Clang 3.7, C++14 441 | - env: COMPILER=clang++-3.7 CPP_VER=14 442 | addons: 443 | apt: 444 | packages: 445 | - clang-3.7 446 | sources: 447 | - ubuntu-toolchain-r-test 448 | - llvm-toolchain-xenial-3.7 449 | 450 | # Clang 3.7, C++11 451 | - env: COMPILER=clang++-3.7 CPP_VER=11 452 | addons: 453 | apt: 454 | packages: 455 | - clang-3.7 456 | sources: 457 | - ubuntu-toolchain-r-test 458 | - llvm-toolchain-xenial-3.7 459 | 460 | # Clang 3.6, C++14 461 | - env: COMPILER=clang++-3.6 CPP_VER=14 462 | addons: 463 | apt: 464 | packages: 465 | - clang-3.6 466 | sources: 467 | - ubuntu-toolchain-r-test 468 | - llvm-toolchain-xenial-3.6 469 | 470 | # Clang 3.6, C++11 471 | - env: COMPILER=clang++-3.6 CPP_VER=11 472 | addons: 473 | apt: 474 | packages: 475 | - clang-3.6 476 | sources: 477 | - ubuntu-toolchain-r-test 478 | - llvm-toolchain-xenial-3.6 479 | 480 | # Clang 3.5, C++11 481 | - env: COMPILER=clang++-3.5 CPP_VER=11 482 | addons: 483 | apt: 484 | packages: 485 | - clang-3.5 486 | sources: 487 | - ubuntu-toolchain-r-test 488 | - llvm-toolchain-xenial-3.5 489 | 490 | install: 491 | - DEPS_DIR="${HOME}/deps" 492 | - mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR} 493 | 494 | - if [[ "${COMPILER}" != "" ]]; then export CXX=${COMPILER}; fi 495 | - ${CXX} --version 496 | 497 | ############################################################################ 498 | # Install libc++ and libc++abi if needed 499 | # Taken from https://github.com/boostorg/hana/blob/master/.travis.yml 500 | ############################################################################ 501 | - | 502 | if [[ "$CPP_VER" == "17" && "$TRAVIS_OS_NAME" == "linux" && "${CXX%%+*}" == "clang" ]]; then 503 | if [[ "${CXX}" == "clang++-3.5" ]]; then LLVM_VERSION="3.5.2"; 504 | elif [[ "${CXX}" == "clang++-3.6" ]]; then LLVM_VERSION="3.6.2"; 505 | elif [[ "${CXX}" == "clang++-3.7" ]]; then LLVM_VERSION="3.7.1"; 506 | elif [[ "${CXX}" == "clang++-3.8" ]]; then LLVM_VERSION="3.8.1"; 507 | elif [[ "${CXX}" == "clang++-3.9" ]]; then LLVM_VERSION="3.9.1"; 508 | elif [[ "${CXX}" == "clang++-4.0" ]]; then LLVM_VERSION="4.0.1"; 509 | elif [[ "${CXX}" == "clang++-5.0" ]]; then LLVM_VERSION="5.0.2"; 510 | elif [[ "${CXX}" == "clang++-6.0" ]]; then LLVM_VERSION="6.0.0"; 511 | elif [[ "${CXX}" == "clang++-7" ]]; then LLVM_VERSION="7.0.0"; 512 | elif [[ "${CXX}" == "clang++-8" ]]; then LLVM_VERSION="8.0.0"; 513 | fi 514 | LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz" 515 | LIBCXX_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxx-${LLVM_VERSION}.src.tar.xz" 516 | LIBCXXABI_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxxabi-${LLVM_VERSION}.src.tar.xz" 517 | mkdir -p llvm llvm/build llvm/projects/libcxx llvm/projects/libcxxabi 518 | travis_retry wget -O - ${LLVM_URL} | tar --strip-components=1 -xJ -C llvm || exit 1 519 | travis_retry wget -O - ${LIBCXX_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxx || exit 1 520 | travis_retry wget -O - ${LIBCXXABI_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxxabi || exit 1 521 | (cd llvm/build && cmake .. -DCMAKE_INSTALL_PREFIX=${DEPS_DIR}/llvm/install) || exit 1 522 | (cd llvm/build/projects/libcxx && make install -j2) || exit 1 523 | (cd llvm/build/projects/libcxxabi && make install -j2) || exit 1 524 | export CXXFLAGS="-isystem ${DEPS_DIR}/llvm/install/include/c++/v1" 525 | export LDFLAGS="-L ${DEPS_DIR}/llvm/install/lib -l c++ -l c++abi" 526 | export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${DEPS_DIR}/llvm/install/lib" 527 | fi 528 | 529 | before_script: 530 | - cd $TRAVIS_BUILD_DIR 531 | - mkdir -p -v build 532 | - cd build 533 | - cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=$COMPILER -DTCB_SPAN_TEST_CXX_STD=$CPP_VER 534 | 535 | script: 536 | - cmake --build . -- -j2 537 | - ctest -j2 538 | 539 | notifications: 540 | email: off -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 3.8) 3 | project(span LANGUAGES CXX) 4 | 5 | enable_testing() 6 | 7 | add_library(span INTERFACE) 8 | target_sources(span INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include/tcb/span.hpp) 9 | target_include_directories(span INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) 10 | target_compile_features(span INTERFACE cxx_std_11) 11 | 12 | set(TCB_SPAN_TEST_CXX_STD 11 CACHE STRING "C++ standard version for testing") 13 | 14 | add_subdirectory(test) 15 | -------------------------------------------------------------------------------- /LICENSE_1_0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![Standard](https://img.shields.io/badge/c%2B%2B-11/14/17/20-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) 3 | [![License](https://img.shields.io/badge/license-BSL-blue.svg)](http://www.boost.org/LICENSE_1_0.txt) 4 | [![Build Status](https://travis-ci.org/tcbrindle/span.svg?branch=master)](https://travis-ci.org/tcbrindle/span) 5 | [![Build status](https://ci.appveyor.com/api/projects/status/ow7cj56s108fs439/branch/master?svg=true)](https://ci.appveyor.com/project/tcbrindle/span/branch/master) 6 | [![Try it on godbolt online](https://img.shields.io/badge/on-godbolt-blue.svg)](https://godbolt.org/z/-vlZZR) 7 | 8 | `std::span` implementation for C++11 and later 9 | ============================================== 10 | 11 | This repository contains a single-header implementation of C++20's `std::span`, 12 | conforming to the C++20 committee draft. 13 | It is compatible with C++11, but will use newer language features if they 14 | are available. 15 | 16 | It differs from the implementation in the [Microsoft GSL](https://github.com/Microsoft/GSL/) 17 | in that it is single-header and does not depend on any other GSL facilities. It 18 | also works with C++11, while the GSL version requires C++14. 19 | 20 | Usage 21 | ----- 22 | 23 | The recommended way to use the implementation simply copy the file `span.hpp` 24 | from `include/tcb/` into your own sources and `#include` it like 25 | any other header. By default, it lives in namespace `tcb`, but this can be 26 | customised by setting the macro `TCB_SPAN_NAMESPACE_NAME` to an appropriate string 27 | before `#include`-ing the header -- or simply edit the source code. 28 | 29 | The rest of the repository contains testing machinery, and is not required for 30 | use. 31 | 32 | Compatibility 33 | ------------- 34 | 35 | This implementation requires a conforming C++11 (or later) compiler, and is tested as far 36 | back as GCC 5, Clang 3.5 and MSVC 2015 Update 3. Older compilers may work, but this is not guaranteed. 37 | 38 | Documentation 39 | ------------- 40 | 41 | Documentation for `std::span` is available [on cppreference](https://en.cppreference.com/w/cpp/container/span). 42 | 43 | Implementation Notes 44 | -------------------- 45 | 46 | ### Bounds Checking ### 47 | 48 | This implementation of `span` includes optional bounds checking, which is handled 49 | either by throwing an exception or by calling `std::terminate()`. 50 | 51 | The default behaviour with C++14 and later is to check the macro `NDEBUG`: 52 | if this is set, bounds checking is disabled. Otherwise, `std::terminate()` will 53 | be called if there is a precondition violation (i.e. the same behaviour as 54 | `assert()`). If you wish to terminate on errors even if `NDEBUG` is set, define 55 | the symbol `TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION` before `#include`-ing the 56 | header. 57 | 58 | Alternatively, if you want to throw on a contract violation, define 59 | `TCB_SPAN_THROW_ON_CONTRACT_VIOLATION`. This will throw an exception of an 60 | implementation-defined type (deriving from `std::logic_error`), allowing 61 | cleanup to happen. Note that defining this symbol will cause the checks to be 62 | run even if `NDEBUG` is set. 63 | 64 | Lastly, if you wish to disable contract checking even in debug builds, 65 | `#define TCB_SPAN_NO_CONTRACT_CHECKING`. 66 | 67 | Under C++11, due to the restrictions on `constexpr` functions, contract checking 68 | is disabled by default even if `NDEBUG` is not set. You can change this by 69 | defining either of the above symbols, but this will result in most of `span`'s 70 | interface becoming non-`constexpr`. 71 | 72 | ### `constexpr` ### 73 | 74 | This implementation is fully `constexpr` under C++17 and later. Under earlier 75 | versions, it is "as `constexpr` as possible". 76 | 77 | Note that even in C++17, it is generally not possible to declare a `span` 78 | as non-default constructed `constexpr` variable, for the same reason that you 79 | cannot form a `constexpr` pointer to a value: it involves taking the address of 80 | a compile-time variable in a way that would be visible at run-time. 81 | You can however use a `span` freely in a `constexpr` function. For example: 82 | 83 | ```cpp 84 | // Okay, even in C++11 85 | constexpr std::ptrdiff_t get_span_size(span span) 86 | { 87 | return span.size(); 88 | } 89 | 90 | constexpr int arr[] = {1, 2, 3}; 91 | constexpr auto size = get_span_size(arr); // Okay 92 | constexpr span span{arr}; // ERROR -- not a constant expression 93 | constexpr const int* p = arr; // ERROR -- same 94 | ``` 95 | 96 | Constructor deduction guides are provided if the compiler supports them. For 97 | older compilers, a set of `make_span()` functions are provided as an extension 98 | which use the same logic, for example: 99 | 100 | ```cpp 101 | constexpr int c_array[] = {1, 2, 3}; 102 | std::array std_array{1, 2, 3}; 103 | const std::vector vec{1, 2, 3}; 104 | 105 | auto s1 = make_span(c_array); // returns span 106 | auto s2 = make_span(std_array); // returns span 107 | auto s3 = make_span(vec); // returns span 108 | ``` 109 | 110 | Alternatives 111 | ------------ 112 | 113 | * [Microsoft/GSL](https://github.com/Microsoft/GSL): The original `span` reference 114 | implementation from which `std::span` was born. 115 | 116 | * [martinmoene/span_lite](https://github.com/martinmoene/span-lite): An 117 | alternative implementation which offers C++98 compatibility. 118 | 119 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | 2 | # Do not build branches of the form "pr/*". By prefixing pull requests coming 3 | # from branches inside the repository with pr/, this avoids building both the 4 | # branch push _and_ the pull request. 5 | # Based on https://github.com/boostorg/hana/blob/master/.travis.yml 6 | branches: 7 | except: 8 | - /pr\/.+/ 9 | 10 | environment: 11 | matrix: 12 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 Preview 13 | CXX_VER: 17 14 | 15 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 Preview 16 | CXX_VER: 14 17 | 18 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 Preview 19 | CXX_VER: 11 20 | 21 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 22 | CXX_VER: 17 23 | 24 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 25 | CXX_VER: 14 26 | 27 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 28 | CXX_VER: 11 29 | 30 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 31 | CXX_VER: 14 32 | 33 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 34 | CXX_VER: 11 35 | 36 | build_script: 37 | - mkdir cmake-build 38 | - cd cmake-build 39 | - cmake .. -DTCB_SPAN_TEST_CXX_STD=%CXX_VER% 40 | - cmake --build . --config Debug 41 | 42 | test_script: 43 | - ctest -j2 44 | -------------------------------------------------------------------------------- /include/tcb/span.hpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | This is an implementation of C++20's std::span 4 | http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/n4820.pdf 5 | */ 6 | 7 | // Copyright Tristan Brindle 2018. 8 | // Distributed under the Boost Software License, Version 1.0. 9 | // (See accompanying file ../../LICENSE_1_0.txt or copy at 10 | // https://www.boost.org/LICENSE_1_0.txt) 11 | 12 | #ifndef TCB_SPAN_HPP_INCLUDED 13 | #define TCB_SPAN_HPP_INCLUDED 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifndef TCB_SPAN_NO_EXCEPTIONS 21 | // Attempt to discover whether we're being compiled with exception support 22 | #if !(defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) 23 | #define TCB_SPAN_NO_EXCEPTIONS 24 | #endif 25 | #endif 26 | 27 | #ifndef TCB_SPAN_NO_EXCEPTIONS 28 | #include 29 | #include 30 | #endif 31 | 32 | // Various feature test macros 33 | 34 | #ifndef TCB_SPAN_NAMESPACE_NAME 35 | #define TCB_SPAN_NAMESPACE_NAME tcb 36 | #endif 37 | 38 | #if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) 39 | #define TCB_SPAN_HAVE_CPP17 40 | #endif 41 | 42 | #if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) 43 | #define TCB_SPAN_HAVE_CPP14 44 | #endif 45 | 46 | namespace TCB_SPAN_NAMESPACE_NAME { 47 | 48 | // Establish default contract checking behavior 49 | #if !defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION) && \ 50 | !defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION) && \ 51 | !defined(TCB_SPAN_NO_CONTRACT_CHECKING) 52 | #if defined(NDEBUG) || !defined(TCB_SPAN_HAVE_CPP14) 53 | #define TCB_SPAN_NO_CONTRACT_CHECKING 54 | #else 55 | #define TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION 56 | #endif 57 | #endif 58 | 59 | #if defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION) 60 | struct contract_violation_error : std::logic_error { 61 | explicit contract_violation_error(const char* msg) : std::logic_error(msg) 62 | {} 63 | }; 64 | 65 | inline void contract_violation(const char* msg) 66 | { 67 | throw contract_violation_error(msg); 68 | } 69 | 70 | #elif defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION) 71 | [[noreturn]] inline void contract_violation(const char* /*unused*/) 72 | { 73 | std::terminate(); 74 | } 75 | #endif 76 | 77 | #if !defined(TCB_SPAN_NO_CONTRACT_CHECKING) 78 | #define TCB_SPAN_STRINGIFY(cond) #cond 79 | #define TCB_SPAN_EXPECT(cond) \ 80 | cond ? (void) 0 : contract_violation("Expected " TCB_SPAN_STRINGIFY(cond)) 81 | #else 82 | #define TCB_SPAN_EXPECT(cond) 83 | #endif 84 | 85 | #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_inline_variables) 86 | #define TCB_SPAN_INLINE_VAR inline 87 | #else 88 | #define TCB_SPAN_INLINE_VAR 89 | #endif 90 | 91 | #if defined(TCB_SPAN_HAVE_CPP14) || \ 92 | (defined(__cpp_constexpr) && __cpp_constexpr >= 201304) 93 | #define TCB_SPAN_HAVE_CPP14_CONSTEXPR 94 | #endif 95 | 96 | #if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR) 97 | #define TCB_SPAN_CONSTEXPR14 constexpr 98 | #else 99 | #define TCB_SPAN_CONSTEXPR14 100 | #endif 101 | 102 | #if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR) && \ 103 | (!defined(_MSC_VER) || _MSC_VER > 1900) 104 | #define TCB_SPAN_CONSTEXPR_ASSIGN constexpr 105 | #else 106 | #define TCB_SPAN_CONSTEXPR_ASSIGN 107 | #endif 108 | 109 | #if defined(TCB_SPAN_NO_CONTRACT_CHECKING) 110 | #define TCB_SPAN_CONSTEXPR11 constexpr 111 | #else 112 | #define TCB_SPAN_CONSTEXPR11 TCB_SPAN_CONSTEXPR14 113 | #endif 114 | 115 | #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_deduction_guides) 116 | #define TCB_SPAN_HAVE_DEDUCTION_GUIDES 117 | #endif 118 | 119 | #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_byte) 120 | #define TCB_SPAN_HAVE_STD_BYTE 121 | #endif 122 | 123 | #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_array_constexpr) 124 | #define TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC 125 | #endif 126 | 127 | #if defined(TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC) 128 | #define TCB_SPAN_ARRAY_CONSTEXPR constexpr 129 | #else 130 | #define TCB_SPAN_ARRAY_CONSTEXPR 131 | #endif 132 | 133 | #ifdef TCB_SPAN_HAVE_STD_BYTE 134 | using byte = std::byte; 135 | #else 136 | using byte = unsigned char; 137 | #endif 138 | 139 | #if defined(TCB_SPAN_HAVE_CPP17) 140 | #define TCB_SPAN_NODISCARD [[nodiscard]] 141 | #else 142 | #define TCB_SPAN_NODISCARD 143 | #endif 144 | 145 | TCB_SPAN_INLINE_VAR constexpr std::size_t dynamic_extent = SIZE_MAX; 146 | 147 | template 148 | class span; 149 | 150 | namespace detail { 151 | 152 | template 153 | struct span_storage { 154 | constexpr span_storage() noexcept = default; 155 | 156 | constexpr span_storage(E* p_ptr, std::size_t /*unused*/) noexcept 157 | : ptr(p_ptr) 158 | {} 159 | 160 | E* ptr = nullptr; 161 | static constexpr std::size_t size = S; 162 | }; 163 | 164 | template 165 | struct span_storage { 166 | constexpr span_storage() noexcept = default; 167 | 168 | constexpr span_storage(E* p_ptr, std::size_t p_size) noexcept 169 | : ptr(p_ptr), size(p_size) 170 | {} 171 | 172 | E* ptr = nullptr; 173 | std::size_t size = 0; 174 | }; 175 | 176 | // Reimplementation of C++17 std::size() and std::data() 177 | #if defined(TCB_SPAN_HAVE_CPP17) || \ 178 | defined(__cpp_lib_nonmember_container_access) 179 | using std::data; 180 | using std::size; 181 | #else 182 | template 183 | constexpr auto size(const C& c) -> decltype(c.size()) 184 | { 185 | return c.size(); 186 | } 187 | 188 | template 189 | constexpr std::size_t size(const T (&)[N]) noexcept 190 | { 191 | return N; 192 | } 193 | 194 | template 195 | constexpr auto data(C& c) -> decltype(c.data()) 196 | { 197 | return c.data(); 198 | } 199 | 200 | template 201 | constexpr auto data(const C& c) -> decltype(c.data()) 202 | { 203 | return c.data(); 204 | } 205 | 206 | template 207 | constexpr T* data(T (&array)[N]) noexcept 208 | { 209 | return array; 210 | } 211 | 212 | template 213 | constexpr const E* data(std::initializer_list il) noexcept 214 | { 215 | return il.begin(); 216 | } 217 | #endif // TCB_SPAN_HAVE_CPP17 218 | 219 | #if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_void_t) 220 | using std::void_t; 221 | #else 222 | template 223 | using void_t = void; 224 | #endif 225 | 226 | template 227 | using uncvref_t = 228 | typename std::remove_cv::type>::type; 229 | 230 | template 231 | struct is_span : std::false_type {}; 232 | 233 | template 234 | struct is_span> : std::true_type {}; 235 | 236 | template 237 | struct is_std_array : std::false_type {}; 238 | 239 | template 240 | struct is_std_array> : std::true_type {}; 241 | 242 | template 243 | struct has_size_and_data : std::false_type {}; 244 | 245 | template 246 | struct has_size_and_data())), 247 | decltype(detail::data(std::declval()))>> 248 | : std::true_type {}; 249 | 250 | template > 251 | struct is_container { 252 | static constexpr bool value = 253 | !is_span::value && !is_std_array::value && 254 | !std::is_array::value && has_size_and_data::value; 255 | }; 256 | 257 | template 258 | using remove_pointer_t = typename std::remove_pointer::type; 259 | 260 | template 261 | struct is_container_element_type_compatible : std::false_type {}; 262 | 263 | template 264 | struct is_container_element_type_compatible< 265 | T, E, 266 | typename std::enable_if< 267 | !std::is_same< 268 | typename std::remove_cv()))>::type, 269 | void>::value && 270 | std::is_convertible< 271 | remove_pointer_t()))> (*)[], 272 | E (*)[]>::value 273 | >::type> 274 | : std::true_type {}; 275 | 276 | template 277 | struct is_complete : std::false_type {}; 278 | 279 | template 280 | struct is_complete : std::true_type {}; 281 | 282 | } // namespace detail 283 | 284 | template 285 | class span { 286 | static_assert(std::is_object::value, 287 | "A span's ElementType must be an object type (not a " 288 | "reference type or void)"); 289 | static_assert(detail::is_complete::value, 290 | "A span's ElementType must be a complete type (not a forward " 291 | "declaration)"); 292 | static_assert(!std::is_abstract::value, 293 | "A span's ElementType cannot be an abstract class type"); 294 | 295 | using storage_type = detail::span_storage; 296 | 297 | public: 298 | // constants and types 299 | using element_type = ElementType; 300 | using value_type = typename std::remove_cv::type; 301 | using size_type = std::size_t; 302 | using difference_type = std::ptrdiff_t; 303 | using pointer = element_type*; 304 | using const_pointer = const element_type*; 305 | using reference = element_type&; 306 | using const_reference = const element_type&; 307 | using iterator = pointer; 308 | using reverse_iterator = std::reverse_iterator; 309 | 310 | static constexpr size_type extent = Extent; 311 | 312 | // [span.cons], span constructors, copy, assignment, and destructor 313 | template < 314 | std::size_t E = Extent, 315 | typename std::enable_if<(E == dynamic_extent || E <= 0), int>::type = 0> 316 | constexpr span() noexcept 317 | {} 318 | 319 | TCB_SPAN_CONSTEXPR11 span(pointer ptr, size_type count) 320 | : storage_(ptr, count) 321 | { 322 | TCB_SPAN_EXPECT(extent == dynamic_extent || count == extent); 323 | } 324 | 325 | TCB_SPAN_CONSTEXPR11 span(pointer first_elem, pointer last_elem) 326 | : storage_(first_elem, last_elem - first_elem) 327 | { 328 | TCB_SPAN_EXPECT(extent == dynamic_extent || 329 | last_elem - first_elem == 330 | static_cast(extent)); 331 | } 332 | 333 | template ::value, 338 | int>::type = 0> 339 | constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N) 340 | {} 341 | 342 | template &, ElementType>::value, 347 | int>::type = 0> 348 | TCB_SPAN_ARRAY_CONSTEXPR span(std::array& arr) noexcept 349 | : storage_(arr.data(), N) 350 | {} 351 | 352 | template &, ElementType>::value, 357 | int>::type = 0> 358 | TCB_SPAN_ARRAY_CONSTEXPR span(const std::array& arr) noexcept 359 | : storage_(arr.data(), N) 360 | {} 361 | 362 | template < 363 | typename Container, std::size_t E = Extent, 364 | typename std::enable_if< 365 | E == dynamic_extent && detail::is_container::value && 366 | detail::is_container_element_type_compatible< 367 | Container&, ElementType>::value, 368 | int>::type = 0> 369 | constexpr span(Container& cont) 370 | : storage_(detail::data(cont), detail::size(cont)) 371 | {} 372 | 373 | template < 374 | typename Container, std::size_t E = Extent, 375 | typename std::enable_if< 376 | E == dynamic_extent && detail::is_container::value && 377 | detail::is_container_element_type_compatible< 378 | const Container&, ElementType>::value, 379 | int>::type = 0> 380 | constexpr span(const Container& cont) 381 | : storage_(detail::data(cont), detail::size(cont)) 382 | {} 383 | 384 | constexpr span(const span& other) noexcept = default; 385 | 386 | template ::value, 392 | int>::type = 0> 393 | constexpr span(const span& other) noexcept 394 | : storage_(other.data(), other.size()) 395 | {} 396 | 397 | ~span() noexcept = default; 398 | 399 | TCB_SPAN_CONSTEXPR_ASSIGN span& 400 | operator=(const span& other) noexcept = default; 401 | 402 | // [span.sub], span subviews 403 | template 404 | TCB_SPAN_CONSTEXPR11 span first() const 405 | { 406 | TCB_SPAN_EXPECT(Count <= size()); 407 | return {data(), Count}; 408 | } 409 | 410 | template 411 | TCB_SPAN_CONSTEXPR11 span last() const 412 | { 413 | TCB_SPAN_EXPECT(Count <= size()); 414 | return {data() + (size() - Count), Count}; 415 | } 416 | 417 | template 418 | using subspan_return_t = 419 | span; 423 | 424 | template 425 | TCB_SPAN_CONSTEXPR11 subspan_return_t subspan() const 426 | { 427 | TCB_SPAN_EXPECT(Offset <= size() && 428 | (Count == dynamic_extent || Offset + Count <= size())); 429 | return {data() + Offset, 430 | Count != dynamic_extent ? Count : size() - Offset}; 431 | } 432 | 433 | TCB_SPAN_CONSTEXPR11 span 434 | first(size_type count) const 435 | { 436 | TCB_SPAN_EXPECT(count <= size()); 437 | return {data(), count}; 438 | } 439 | 440 | TCB_SPAN_CONSTEXPR11 span 441 | last(size_type count) const 442 | { 443 | TCB_SPAN_EXPECT(count <= size()); 444 | return {data() + (size() - count), count}; 445 | } 446 | 447 | TCB_SPAN_CONSTEXPR11 span 448 | subspan(size_type offset, size_type count = dynamic_extent) const 449 | { 450 | TCB_SPAN_EXPECT(offset <= size() && 451 | (count == dynamic_extent || offset + count <= size())); 452 | return {data() + offset, 453 | count == dynamic_extent ? size() - offset : count}; 454 | } 455 | 456 | // [span.obs], span observers 457 | constexpr size_type size() const noexcept { return storage_.size; } 458 | 459 | constexpr size_type size_bytes() const noexcept 460 | { 461 | return size() * sizeof(element_type); 462 | } 463 | 464 | TCB_SPAN_NODISCARD constexpr bool empty() const noexcept 465 | { 466 | return size() == 0; 467 | } 468 | 469 | // [span.elem], span element access 470 | TCB_SPAN_CONSTEXPR11 reference operator[](size_type idx) const 471 | { 472 | TCB_SPAN_EXPECT(idx < size()); 473 | return *(data() + idx); 474 | } 475 | 476 | TCB_SPAN_CONSTEXPR11 reference front() const 477 | { 478 | TCB_SPAN_EXPECT(!empty()); 479 | return *data(); 480 | } 481 | 482 | TCB_SPAN_CONSTEXPR11 reference back() const 483 | { 484 | TCB_SPAN_EXPECT(!empty()); 485 | return *(data() + (size() - 1)); 486 | } 487 | 488 | constexpr pointer data() const noexcept { return storage_.ptr; } 489 | 490 | // [span.iterators], span iterator support 491 | constexpr iterator begin() const noexcept { return data(); } 492 | 493 | constexpr iterator end() const noexcept { return data() + size(); } 494 | 495 | TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rbegin() const noexcept 496 | { 497 | return reverse_iterator(end()); 498 | } 499 | 500 | TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rend() const noexcept 501 | { 502 | return reverse_iterator(begin()); 503 | } 504 | 505 | private: 506 | storage_type storage_{}; 507 | }; 508 | 509 | #ifdef TCB_SPAN_HAVE_DEDUCTION_GUIDES 510 | 511 | /* Deduction Guides */ 512 | template 513 | span(T (&)[N])->span; 514 | 515 | template 516 | span(std::array&)->span; 517 | 518 | template 519 | span(const std::array&)->span; 520 | 521 | template 522 | span(Container&)->span()))>::type>; 524 | 525 | template 526 | span(const Container&)->span; 527 | 528 | #endif // TCB_HAVE_DEDUCTION_GUIDES 529 | 530 | template 531 | constexpr span 532 | make_span(span s) noexcept 533 | { 534 | return s; 535 | } 536 | 537 | template 538 | constexpr span make_span(T (&arr)[N]) noexcept 539 | { 540 | return {arr}; 541 | } 542 | 543 | template 544 | TCB_SPAN_ARRAY_CONSTEXPR span make_span(std::array& arr) noexcept 545 | { 546 | return {arr}; 547 | } 548 | 549 | template 550 | TCB_SPAN_ARRAY_CONSTEXPR span 551 | make_span(const std::array& arr) noexcept 552 | { 553 | return {arr}; 554 | } 555 | 556 | template 557 | constexpr span()))>::type> 559 | make_span(Container& cont) 560 | { 561 | return {cont}; 562 | } 563 | 564 | template 565 | constexpr span 566 | make_span(const Container& cont) 567 | { 568 | return {cont}; 569 | } 570 | 571 | template 572 | span 574 | as_bytes(span s) noexcept 575 | { 576 | return {reinterpret_cast(s.data()), s.size_bytes()}; 577 | } 578 | 579 | template < 580 | class ElementType, size_t Extent, 581 | typename std::enable_if::value, int>::type = 0> 582 | span 584 | as_writable_bytes(span s) noexcept 585 | { 586 | return {reinterpret_cast(s.data()), s.size_bytes()}; 587 | } 588 | 589 | template 590 | constexpr auto get(span s) -> decltype(s[N]) 591 | { 592 | return s[N]; 593 | } 594 | 595 | } // namespace TCB_SPAN_NAMESPACE_NAME 596 | 597 | namespace std { 598 | 599 | template 600 | class tuple_size> 601 | : public integral_constant {}; 602 | 603 | template 604 | class tuple_size>; // not defined 606 | 607 | template 608 | class tuple_element> { 609 | public: 610 | static_assert(Extent != TCB_SPAN_NAMESPACE_NAME::dynamic_extent && 611 | I < Extent, 612 | ""); 613 | using type = ElementType; 614 | }; 615 | 616 | } // end namespace std 617 | 618 | #endif // TCB_SPAN_HPP_INCLUDED 619 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 3 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic") 4 | endif() 5 | 6 | if(MSVC) 7 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /permissive-") 8 | endif() 9 | 10 | set(CMAKE_CXX_EXTENSIONS Off) 11 | 12 | add_library(catch_main catch_main.cpp) 13 | set_target_properties(catch_main PROPERTIES 14 | CXX_STANDARD ${TCB_SPAN_TEST_CXX_STD}) 15 | 16 | set(TEST_FILES 17 | test_span.cpp 18 | ) 19 | 20 | if (${TCB_SPAN_TEST_CXX_STD} GREATER 17 OR ${TCB_SPAN_TEST_CXX_STD} EQUAL 17) 21 | list(APPEND TEST_FILES 22 | test_deduction_guides.cpp 23 | test_structured_bindings.cpp) 24 | endif() 25 | 26 | add_executable(test_span ${TEST_FILES}) 27 | target_link_libraries(test_span PUBLIC span catch_main) 28 | set_target_properties(test_span PROPERTIES 29 | CXX_STANDARD ${TCB_SPAN_TEST_CXX_STD}) 30 | add_test(test_span test_span) 31 | 32 | add_executable(test_span_contract_checking 33 | test_contract_checking.cpp) 34 | target_link_libraries(test_span_contract_checking PUBLIC span catch_main) 35 | set_target_properties(test_span_contract_checking PROPERTIES 36 | CXX_STANDARD ${TCB_SPAN_TEST_CXX_STD}) 37 | add_test(test_contract_checking test_span_contract_checking) -------------------------------------------------------------------------------- /test/catch_main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #define CATCH_CONFIG_MAIN 3 | #include "catch.hpp" -------------------------------------------------------------------------------- /test/test_contract_checking.cpp: -------------------------------------------------------------------------------- 1 | 2 | #define TCB_SPAN_NO_DEPRECATION_WARNINGS 3 | #define TCB_SPAN_THROW_ON_CONTRACT_VIOLATION 4 | #include 5 | 6 | #include "catch.hpp" 7 | 8 | #include 9 | 10 | using tcb::make_span; 11 | using tcb::span; 12 | 13 | #define TEST(expr) REQUIRE_THROWS_AS(expr, std::logic_error) 14 | 15 | TEST_CASE("span(ptr, length)") 16 | { 17 | std::vector vec{1, 2, 3}; 18 | 19 | TEST((tcb::span{nullptr, 1})); 20 | TEST((tcb::span{vec.data(), 1})); 21 | } 22 | 23 | TEST_CASE("span(ptr, ptr)") 24 | { 25 | std::vector vec{1, 2, 3}; 26 | 27 | TEST((tcb::span{nullptr, nullptr})); 28 | TEST((tcb::span{vec.data(), vec.data() + 1})); 29 | } 30 | 31 | TEST_CASE("fixed-size subspans") 32 | { 33 | SECTION("first()") 34 | { 35 | std::vector vec{1, 2, 3}; 36 | auto s = make_span(vec); 37 | TEST(s.first<4>()); 38 | } 39 | 40 | SECTION("last()") 41 | { 42 | std::vector vec{1, 2, 3}; 43 | auto s = make_span(vec); 44 | TEST(s.last<4>()); 45 | } 46 | 47 | SECTION("subspan()") 48 | { 49 | std::vector vec{1, 2, 3, 4, 5}; 50 | auto s = make_span(vec); 51 | TEST(s.subspan<6>()); 52 | } 53 | 54 | SECTION("subspan()") 55 | { 56 | std::vector vec{1, 2, 3, 4, 5}; 57 | auto s = make_span(vec); 58 | // TEST((s.subspan<0, -2>())); // turns out this gets static_assert'd in 59 | // the return type 60 | TEST((s.subspan<0, 6>())); 61 | } 62 | } 63 | 64 | TEST_CASE("dynamic-size subspans") 65 | { 66 | SECTION("first(n)") 67 | { 68 | std::vector vec{1, 2, 3}; 69 | auto s = make_span(vec); 70 | TEST(s.first(-1)); 71 | TEST(s.first(4)); 72 | } 73 | 74 | SECTION("last(n)") 75 | { 76 | std::vector vec{1, 2, 3}; 77 | auto s = make_span(vec); 78 | TEST(s.last(-1)); 79 | TEST(s.last(4)); 80 | } 81 | 82 | SECTION("subspan(n)") 83 | { 84 | std::vector vec{1, 2, 3, 4, 5}; 85 | auto s = make_span(vec); 86 | TEST(s.subspan(-1)); 87 | TEST(s.subspan(6)); 88 | } 89 | 90 | SECTION("subspan(n, m)") 91 | { 92 | std::vector vec{1, 2, 3, 4, 5}; 93 | auto s = make_span(vec); 94 | TEST(s.subspan(0, -2)); 95 | TEST(s.subspan(0, 6)); 96 | } 97 | } 98 | 99 | TEST_CASE("Member access") 100 | { 101 | std::vector vec{1, 2, 3}; 102 | auto s = make_span(vec); 103 | 104 | TEST(s[-2]); 105 | TEST(s[42]); 106 | } 107 | 108 | TEST_CASE("front() and back()") 109 | { 110 | constexpr span s{}; 111 | 112 | TEST(s.front()); 113 | TEST(s.back()); 114 | } -------------------------------------------------------------------------------- /test/test_deduction_guides.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "catch.hpp" 5 | 6 | #include 7 | 8 | using tcb::span; 9 | 10 | #ifdef TCB_SPAN_HAVE_DEDUCTION_GUIDES 11 | 12 | namespace { 13 | 14 | template 15 | constexpr bool equal(R1&& r1, R2&& r2) 16 | { 17 | auto first1 = std::begin(r1); 18 | const auto last1 = std::end(r1); 19 | auto first2 = std::begin(r2); 20 | const auto last2 = std::end(r2); 21 | 22 | while (first1 != last1 && first2 != last2) { 23 | if (*first1 != *first2) { 24 | return false; 25 | } 26 | ++first1; 27 | ++first2; 28 | } 29 | 30 | return true; 31 | } 32 | 33 | constexpr bool test_raw_array() 34 | { 35 | int arr[] = {1, 2, 3}; 36 | auto s = span{arr}; 37 | static_assert(std::is_same_v>); 38 | 39 | return equal(arr, s); 40 | } 41 | 42 | constexpr bool test_const_raw_array() 43 | { 44 | constexpr int arr[] = {1, 2, 3}; 45 | auto s = span{arr}; 46 | static_assert(std::is_same_v>); 47 | 48 | return equal(arr, s); 49 | } 50 | 51 | TCB_SPAN_ARRAY_CONSTEXPR bool test_std_array() 52 | { 53 | auto arr = std::array{1, 2, 3}; 54 | auto s = span{arr}; 55 | static_assert(std::is_same_v>); 56 | 57 | return equal(arr, s); 58 | } 59 | 60 | TCB_SPAN_ARRAY_CONSTEXPR bool test_const_std_array() 61 | { 62 | const auto arr = std::array{1, 2, 3}; 63 | auto s = span{arr}; 64 | static_assert(std::is_same_v>); 65 | 66 | return equal(arr, s); 67 | } 68 | 69 | TCB_SPAN_ARRAY_CONSTEXPR bool test_std_array_const() 70 | { 71 | auto arr = std::array{1, 2, 3}; 72 | auto s = span{arr}; 73 | static_assert(std::is_same_v>); 74 | 75 | return equal(arr, s); 76 | } 77 | 78 | TCB_SPAN_ARRAY_CONSTEXPR bool test_const_std_array_const() 79 | { 80 | const auto arr = std::array{1, 2, 3}; 81 | auto s = span{arr}; 82 | static_assert(std::is_same_v>); 83 | 84 | return equal(arr, s); 85 | } 86 | 87 | bool test_vec() 88 | { 89 | auto arr = std::vector{1, 2, 3}; 90 | auto s = span{arr}; 91 | static_assert(std::is_same_v>); 92 | 93 | return equal(arr, s); 94 | } 95 | 96 | bool test_const_vec() 97 | { 98 | const auto arr = std::vector{1, 2, 3}; 99 | auto s = span{arr}; 100 | static_assert(std::is_same_v>); 101 | 102 | return equal(arr, s); 103 | } 104 | 105 | #ifdef TCB_SPAN_HAVE_CPP17 106 | bool test_string_view() 107 | { 108 | auto str = std::string_view{"hello"}; 109 | auto s = span{str}; 110 | static_assert(std::is_same_v>); 111 | 112 | return equal(str, s); 113 | } 114 | 115 | bool test_const_string_view() 116 | { 117 | const auto str = std::string_view{"hello"}; 118 | auto s = span{str}; 119 | static_assert(std::is_same_v>); 120 | 121 | return equal(str, s); 122 | } 123 | #endif // TCB_SPAN_HAVE_CPP17 124 | 125 | } 126 | 127 | TEST_CASE("Deduction from raw arrays") 128 | { 129 | static_assert(test_raw_array()); 130 | static_assert(test_const_raw_array()); 131 | #ifdef TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC 132 | static_assert(test_std_array()); 133 | static_assert(test_const_std_array()); 134 | #endif 135 | 136 | REQUIRE(test_std_array()); 137 | REQUIRE(test_const_std_array()); 138 | REQUIRE(test_std_array_const()); 139 | REQUIRE(test_const_std_array_const()); 140 | REQUIRE(test_vec()); 141 | REQUIRE(test_const_vec()); 142 | #ifdef TCB_SPAN_HAVE_CPP17 143 | REQUIRE(test_string_view()); 144 | REQUIRE(test_const_string_view()); 145 | #endif // TCB_SPAN_HAVE_CPP17 146 | } 147 | 148 | #endif // TCB_SPAN_HAVE_DEDUCTION_GUIDES 149 | -------------------------------------------------------------------------------- /test/test_span.cpp: -------------------------------------------------------------------------------- 1 | 2 | #define TCB_SPAN_NO_DEPRECATION_WARNINGS 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "catch.hpp" 11 | 12 | using tcb::span; 13 | 14 | struct base {}; 15 | struct derived : base {}; 16 | 17 | TEST_CASE("default construction") 18 | { 19 | static_assert(std::is_nothrow_default_constructible>::value, ""); 20 | static_assert(std::is_nothrow_default_constructible>::value, 21 | ""); 22 | static_assert(!std::is_default_constructible>::value, ""); 23 | 24 | SECTION("dynamic size") 25 | { 26 | constexpr span s{}; 27 | static_assert(s.size() == 0, ""); 28 | static_assert(s.data() == nullptr, ""); 29 | // This causes an ICE on MSVC 30 | #ifndef _MSC_VER 31 | static_assert(s.begin() == s.end(), ""); 32 | #else 33 | REQUIRE(s.begin() == s.end()); 34 | #endif 35 | } 36 | 37 | SECTION("fixed size") 38 | { 39 | constexpr span s{}; 40 | static_assert(s.size() == 0, ""); 41 | static_assert(s.data() == nullptr, ""); 42 | #ifndef _MSC_VER 43 | static_assert(s.begin() == s.end(), ""); 44 | #else 45 | REQUIRE(s.begin() == s.end()); 46 | #endif 47 | } 48 | } 49 | 50 | TEST_CASE("(pointer, length) construction") 51 | { 52 | static_assert(std::is_constructible, int*, int>::value, ""); 53 | static_assert(std::is_constructible, int*, int>::value, ""); 54 | static_assert( 55 | std::is_constructible, const int*, int>::value, ""); 56 | 57 | static_assert(std::is_constructible, int*, int>::value, ""); 58 | static_assert(std::is_constructible, int*, int>::value, 59 | ""); 60 | static_assert( 61 | std::is_constructible, const int*, int>::value, ""); 62 | 63 | SECTION("dynamic size") 64 | { 65 | int arr[] = {1, 2, 3}; 66 | span s(arr, 3); 67 | 68 | REQUIRE(s.size() == 3); 69 | REQUIRE(s.data() == arr); 70 | REQUIRE(s.begin() == std::begin(arr)); 71 | REQUIRE(s.end() == std::end(arr)); 72 | } 73 | 74 | SECTION("fixed size") 75 | { 76 | int arr[] = {1, 2, 3}; 77 | span s(arr, 3); 78 | 79 | REQUIRE(s.size() == 3); 80 | REQUIRE(s.data() == arr); 81 | REQUIRE(s.begin() == std::begin(arr)); 82 | REQUIRE(s.end() == std::end(arr)); 83 | } 84 | } 85 | 86 | TEST_CASE("(pointer, pointer) construction") 87 | { 88 | static_assert(std::is_constructible, int*, int*>::value, ""); 89 | static_assert(!std::is_constructible, float*, float*>::value, ""); 90 | static_assert(std::is_constructible, int*, int*>::value, ""); 91 | static_assert(!std::is_constructible, float*, float*>::value, 92 | ""); 93 | 94 | SECTION("dynamic size") 95 | { 96 | int arr[] = {1, 2, 3}; 97 | span s{arr, arr + 3}; 98 | REQUIRE(s.size() == 3); 99 | REQUIRE(s.data() == arr); 100 | REQUIRE(s.begin() == std::begin(arr)); 101 | REQUIRE(s.end() == std::end(arr)); 102 | } 103 | 104 | SECTION("fixed size") 105 | { 106 | int arr[] = {1, 2, 3}; 107 | span s{arr, arr + 3}; 108 | REQUIRE(s.size() == 3); 109 | REQUIRE(s.data() == arr); 110 | REQUIRE(s.begin() == std::begin(arr)); 111 | REQUIRE(s.end() == std::end(arr)); 112 | } 113 | } 114 | 115 | TEST_CASE("C array construction") 116 | { 117 | using int_array_t = int[3]; 118 | using float_array_t = float[3]; 119 | 120 | static_assert(std::is_nothrow_constructible, int_array_t&>::value, 121 | ""); 122 | static_assert(!std::is_constructible, int_array_t const&>::value, 123 | ""); 124 | static_assert(!std::is_constructible, float_array_t>::value, ""); 125 | 126 | static_assert( 127 | std::is_nothrow_constructible, int_array_t&>::value, 128 | ""); 129 | static_assert(std::is_nothrow_constructible, 130 | int_array_t const&>::value, 131 | ""); 132 | static_assert(!std::is_constructible, float_array_t>::value, 133 | ""); 134 | 135 | static_assert( 136 | std::is_nothrow_constructible, int_array_t&>::value, ""); 137 | static_assert( 138 | !std::is_constructible, int_array_t const&>::value, ""); 139 | static_assert(!std::is_constructible, float_array_t&>::value, 140 | ""); 141 | 142 | static_assert( 143 | std::is_nothrow_constructible, int_array_t&>::value, 144 | ""); 145 | static_assert(std::is_nothrow_constructible, 146 | int_array_t const&>::value, 147 | ""); 148 | static_assert( 149 | !std::is_constructible, float_array_t>::value, ""); 150 | 151 | static_assert(!std::is_constructible, int_array_t&>::value, 152 | ""); 153 | static_assert( 154 | !std::is_constructible, int_array_t const&>::value, ""); 155 | static_assert(!std::is_constructible, float_array_t&>::value, 156 | ""); 157 | 158 | static_assert( 159 | !std::is_constructible, int_array_t&>::value, ""); 160 | static_assert( 161 | !std::is_constructible, int_array_t const&>::value, 162 | ""); 163 | static_assert( 164 | !std::is_constructible, float_array_t&>::value, ""); 165 | 166 | SECTION("non-const, dynamic size") 167 | { 168 | int arr[] = {1, 2, 3}; 169 | span s{arr}; 170 | REQUIRE(s.size() == 3); 171 | REQUIRE(s.data() == arr); 172 | REQUIRE(s.begin() == std::begin(arr)); 173 | REQUIRE(s.end() == std::end(arr)); 174 | } 175 | 176 | SECTION("const, dynamic size") 177 | { 178 | int arr[] = {1, 2, 3}; 179 | span s{arr}; 180 | REQUIRE(s.size() == 3); 181 | REQUIRE(s.data() == arr); 182 | REQUIRE(s.begin() == std::begin(arr)); 183 | REQUIRE(s.end() == std::end(arr)); 184 | } 185 | 186 | SECTION("non-const, static size") 187 | { 188 | int arr[] = {1, 2, 3}; 189 | span s{arr}; 190 | REQUIRE(s.size() == 3); 191 | REQUIRE(s.data() == arr); 192 | REQUIRE(s.begin() == std::begin(arr)); 193 | REQUIRE(s.end() == std::end(arr)); 194 | } 195 | 196 | SECTION("const, dynamic size") 197 | { 198 | int arr[] = {1, 2, 3}; 199 | span s{arr}; 200 | REQUIRE(s.size() == 3); 201 | REQUIRE(s.data() == arr); 202 | REQUIRE(s.begin() == std::begin(arr)); 203 | REQUIRE(s.end() == std::end(arr)); 204 | } 205 | } 206 | 207 | TEST_CASE("std::array construction") 208 | { 209 | using int_array_t = std::array; 210 | using float_array_t = std::array; 211 | using zero_array_t = std::array; 212 | 213 | static_assert(std::is_nothrow_constructible, int_array_t&>::value, 214 | ""); 215 | static_assert(!std::is_constructible, int_array_t const&>::value, 216 | ""); 217 | static_assert(!std::is_constructible, float_array_t>::value, ""); 218 | 219 | static_assert( 220 | std::is_nothrow_constructible, int_array_t&>::value, 221 | ""); 222 | static_assert(std::is_nothrow_constructible, 223 | int_array_t const&>::value, 224 | ""); 225 | static_assert( 226 | !std::is_constructible, float_array_t const&>::value, 227 | ""); 228 | 229 | static_assert( 230 | std::is_nothrow_constructible, int_array_t&>::value, ""); 231 | static_assert( 232 | !std::is_constructible, int_array_t const&>::value, ""); 233 | static_assert(!std::is_constructible, float_array_t>::value, 234 | ""); 235 | 236 | static_assert( 237 | std::is_nothrow_constructible, int_array_t&>::value, 238 | ""); 239 | static_assert(std::is_nothrow_constructible, 240 | int_array_t const&>::value, 241 | ""); 242 | static_assert( 243 | !std::is_constructible, float_array_t const&>::value, 244 | ""); 245 | 246 | static_assert(!std::is_constructible, int_array_t&>::value, 247 | ""); 248 | static_assert( 249 | !std::is_constructible, int_array_t const&>::value, ""); 250 | static_assert( 251 | !std::is_constructible, float_array_t const&>::value, ""); 252 | 253 | static_assert( 254 | !std::is_constructible, int_array_t&>::value, ""); 255 | static_assert( 256 | !std::is_constructible, int_array_t const&>::value, 257 | ""); 258 | static_assert( 259 | !std::is_constructible, float_array_t&>::value, ""); 260 | 261 | static_assert(std::is_constructible, zero_array_t&>::value, ""); 262 | static_assert(!std::is_constructible, const zero_array_t&>::value, 263 | ""); 264 | static_assert(std::is_constructible, zero_array_t&>::value, 265 | ""); 266 | static_assert( 267 | std::is_constructible, const zero_array_t&>::value, ""); 268 | 269 | static_assert(std::is_constructible, zero_array_t&>::value, 270 | ""); 271 | static_assert( 272 | !std::is_constructible, const zero_array_t&>::value, ""); 273 | static_assert( 274 | std::is_constructible, zero_array_t&>::value, ""); 275 | static_assert( 276 | std::is_constructible, const zero_array_t&>::value, 277 | ""); 278 | 279 | SECTION("non-const, dynamic size") 280 | { 281 | int_array_t arr = {1, 2, 3}; 282 | span s{arr}; 283 | REQUIRE(s.size() == 3); 284 | REQUIRE(s.data() == arr.data()); 285 | REQUIRE(s.begin() == arr.data()); 286 | REQUIRE(s.end() == arr.data() + 3); 287 | } 288 | 289 | SECTION("const, dynamic size") 290 | { 291 | int_array_t arr = {1, 2, 3}; 292 | span s{arr}; 293 | REQUIRE(s.size() == 3); 294 | REQUIRE(s.data() == arr.data()); 295 | REQUIRE(s.begin() == arr.data()); 296 | REQUIRE(s.end() == arr.data() + 3); 297 | } 298 | 299 | SECTION("non-const, static size") 300 | { 301 | int_array_t arr = {1, 2, 3}; 302 | span s{arr}; 303 | REQUIRE(s.size() == 3); 304 | REQUIRE(s.data() == arr.data()); 305 | REQUIRE(s.begin() == arr.data()); 306 | REQUIRE(s.end() == arr.data() + 3); 307 | } 308 | 309 | SECTION("const, dynamic size") 310 | { 311 | int_array_t arr = {1, 2, 3}; 312 | span s{arr}; 313 | REQUIRE(s.size() == 3); 314 | REQUIRE(s.data() == arr.data()); 315 | REQUIRE(s.begin() == arr.data()); 316 | REQUIRE(s.end() == arr.data() + 3); 317 | } 318 | } 319 | 320 | TEST_CASE("Construction from other containers") 321 | { 322 | using vec_t = std::vector; 323 | using deque_t = std::deque; 324 | 325 | static_assert(std::is_constructible, vec_t&>::value, ""); 326 | static_assert(!std::is_constructible, const vec_t&>::value, ""); 327 | static_assert(!std::is_constructible, const deque_t&>::value, ""); 328 | 329 | static_assert(std::is_constructible, vec_t&>::value, ""); 330 | static_assert(std::is_constructible, const vec_t&>::value, 331 | ""); 332 | static_assert( 333 | !std::is_constructible, const deque_t&>::value, ""); 334 | 335 | static_assert(!std::is_constructible, vec_t&>::value, ""); 336 | static_assert(!std::is_constructible, const vec_t&>::value, 337 | ""); 338 | static_assert(!std::is_constructible, const deque_t&>::value, 339 | ""); 340 | 341 | static_assert(!std::is_constructible, vec_t&>::value, ""); 342 | static_assert( 343 | !std::is_constructible, const vec_t&>::value, ""); 344 | static_assert( 345 | !std::is_constructible, const deque_t&>::value, ""); 346 | 347 | // vector is not contiguous and cannot be converted to span 348 | // Regression test for https://github.com/tcbrindle/span/issues/24 349 | static_assert( 350 | !std::is_constructible, std::vector&>::value, ""); 351 | static_assert(!std::is_constructible, 352 | const std::vector&>::value, ""); 353 | 354 | SECTION("non-const, dynamic size") 355 | { 356 | vec_t arr = {1, 2, 3}; 357 | span s{arr}; 358 | REQUIRE(s.size() == 3); 359 | REQUIRE(s.data() == arr.data()); 360 | REQUIRE(s.begin() == arr.data()); 361 | REQUIRE(s.end() == arr.data() + 3); 362 | } 363 | 364 | SECTION("const, dynamic size") 365 | { 366 | vec_t arr = {1, 2, 3}; 367 | span s{arr}; 368 | REQUIRE(s.size() == 3); 369 | REQUIRE(s.data() == arr.data()); 370 | REQUIRE(s.begin() == arr.data()); 371 | REQUIRE(s.end() == arr.data() + 3); 372 | } 373 | 374 | SECTION("non-const, static size") 375 | { 376 | std::array arr = {1, 2, 3}; 377 | span s{arr}; 378 | REQUIRE(s.size() == 3); 379 | REQUIRE(s.data() == arr.data()); 380 | REQUIRE(s.begin() == arr.data()); 381 | REQUIRE(s.end() == arr.data() + 3); 382 | } 383 | 384 | SECTION("const, dynamic size") 385 | { 386 | std::array arr = {1, 2, 3}; 387 | span s{arr}; 388 | REQUIRE(s.size() == 3); 389 | REQUIRE(s.data() == arr.data()); 390 | REQUIRE(s.begin() == arr.data()); 391 | REQUIRE(s.end() == arr.data() + 3); 392 | } 393 | } 394 | 395 | TEST_CASE("construction from spans of different size") 396 | { 397 | using zero_span = span; 398 | using zero_const_span = span; 399 | using big_span = span; 400 | using big_const_span = span; 401 | using dynamic_span = span; 402 | using dynamic_const_span = span; 403 | 404 | static_assert(std::is_trivially_copyable::value, ""); 405 | static_assert(std::is_trivially_move_constructible::value, ""); 406 | static_assert(!std::is_constructible::value, 407 | ""); 408 | static_assert(!std::is_constructible::value, ""); 409 | static_assert(!std::is_constructible::value, ""); 410 | static_assert(std::is_nothrow_constructible::value, 411 | ""); 412 | static_assert(!std::is_constructible::value, 413 | ""); 414 | 415 | static_assert( 416 | std::is_nothrow_constructible::value, ""); 417 | static_assert(std::is_trivially_copyable::value, ""); 418 | static_assert(std::is_trivially_move_constructible::value, 419 | ""); 420 | static_assert(!std::is_constructible::value, ""); 421 | static_assert( 422 | !std::is_constructible::value, ""); 423 | static_assert( 424 | std::is_nothrow_constructible::value, 425 | ""); 426 | static_assert(std::is_nothrow_constructible::value, 428 | ""); 429 | 430 | static_assert(!std::is_constructible::value, ""); 431 | static_assert(!std::is_constructible::value, ""); 432 | static_assert(std::is_trivially_copyable::value, ""); 433 | static_assert(std::is_trivially_move_constructible::value, ""); 434 | static_assert(!std::is_constructible::value, ""); 435 | static_assert(std::is_nothrow_constructible::value, 436 | ""); 437 | static_assert(!std::is_constructible::value, 438 | ""); 439 | 440 | static_assert(!std::is_constructible::value, ""); 441 | static_assert( 442 | !std::is_constructible::value, ""); 443 | static_assert(std::is_trivially_copyable::value, ""); 444 | static_assert(std::is_trivially_move_constructible::value, 445 | ""); 446 | static_assert( 447 | std::is_nothrow_constructible::value, ""); 448 | static_assert( 449 | std::is_nothrow_constructible::value, ""); 450 | static_assert(std::is_nothrow_constructible::value, 452 | ""); 453 | 454 | static_assert(std::is_nothrow_constructible::value, 455 | ""); 456 | static_assert(!std::is_constructible::value, 457 | ""); 458 | static_assert(std::is_nothrow_constructible::value, 459 | ""); 460 | static_assert(!std::is_constructible::value, 461 | ""); 462 | static_assert(std::is_trivially_copyable::value, ""); 463 | static_assert(std::is_trivially_move_constructible::value, 464 | ""); 465 | static_assert( 466 | !std::is_constructible::value, ""); 467 | 468 | static_assert( 469 | std::is_nothrow_constructible::value, 470 | ""); 471 | static_assert(std::is_nothrow_constructible::value, 473 | ""); 474 | static_assert( 475 | std::is_nothrow_constructible::value, ""); 476 | static_assert(std::is_nothrow_constructible::value, 478 | ""); 479 | static_assert( 480 | std::is_nothrow_constructible::value, 481 | ""); 482 | static_assert(std::is_trivially_copyable::value, ""); 483 | static_assert( 484 | std::is_trivially_move_constructible::value, ""); 485 | 486 | constexpr zero_const_span s0{}; 487 | constexpr dynamic_const_span d{s0}; 488 | 489 | static_assert(d.size() == 0, ""); 490 | static_assert(d.data() == nullptr, ""); 491 | #ifndef _MSC_VER 492 | static_assert(d.begin() == d.end(), ""); 493 | #else 494 | REQUIRE(d.begin() == d.end()); 495 | #endif 496 | } 497 | 498 | TEST_CASE("member subview operations") 499 | { 500 | SECTION("first") 501 | { 502 | int arr[] = {1, 2, 3, 4, 5}; 503 | span s{arr}; 504 | auto f = s.first<3>(); 505 | 506 | static_assert(std::is_same>::value, ""); 507 | REQUIRE(f.size() == 3); 508 | REQUIRE(f.data() == arr); 509 | REQUIRE(f.begin() == arr); 510 | REQUIRE(f.end() == arr + 3); 511 | } 512 | 513 | SECTION("last") 514 | { 515 | int arr[] = {1, 2, 3, 4, 5}; 516 | span s{arr}; 517 | auto l = s.last<3>(); 518 | 519 | static_assert(std::is_same>::value, ""); 520 | REQUIRE(l.size() == 3); 521 | REQUIRE(l.data() == arr + 2); 522 | REQUIRE(l.begin() == arr + 2); 523 | REQUIRE(l.end() == std::end(arr)); 524 | } 525 | 526 | SECTION("subspan") 527 | { 528 | int arr[] = {1, 2, 3, 4, 5}; 529 | span s{arr}; 530 | auto ss = s.subspan<1, 2>(); 531 | 532 | static_assert(std::is_same>::value, ""); 533 | REQUIRE(ss.size() == 2); 534 | REQUIRE(ss.data() == arr + 1); 535 | REQUIRE(ss.begin() == arr + 1); 536 | REQUIRE(ss.end() == arr + 1 + 2); 537 | } 538 | 539 | SECTION("first(n)") 540 | { 541 | int arr[] = {1, 2, 3, 4, 5}; 542 | span s{arr}; 543 | auto f = s.first(3); 544 | 545 | static_assert(std::is_same>::value, ""); 546 | REQUIRE(f.size() == 3); 547 | REQUIRE(f.data() == arr); 548 | REQUIRE(f.begin() == arr); 549 | REQUIRE(f.end() == arr + 3); 550 | } 551 | 552 | SECTION("last(n)") 553 | { 554 | int arr[] = {1, 2, 3, 4, 5}; 555 | span s{arr}; 556 | auto l = s.last(3); 557 | 558 | static_assert(std::is_same>::value, ""); 559 | REQUIRE(l.size() == 3); 560 | REQUIRE(l.data() == arr + 2); 561 | REQUIRE(l.begin() == arr + 2); 562 | REQUIRE(l.end() == std::end(arr)); 563 | } 564 | 565 | SECTION("subspan(n)") 566 | { 567 | int arr[] = {1, 2, 3, 4, 5}; 568 | span s{arr}; 569 | auto ss = s.subspan(1, 2); 570 | 571 | static_assert(std::is_same>::value, ""); 572 | REQUIRE(ss.size() == 2); 573 | REQUIRE(ss.data() == arr + 1); 574 | REQUIRE(ss.begin() == arr + 1); 575 | REQUIRE(ss.end() == arr + 1 + 2); 576 | } 577 | 578 | // TODO: Test all the dynamic subspan possibilities 579 | } 580 | 581 | TEST_CASE("span observers") 582 | { 583 | // We already use this everywhere, but whatever 584 | constexpr span empty{}; 585 | static_assert(empty.size() == 0, ""); 586 | static_assert(empty.empty(), ""); 587 | 588 | constexpr int arr[] = {1, 2, 3}; 589 | static_assert(span{arr}.size() == 3, ""); 590 | static_assert(!span{arr}.empty(), ""); 591 | } 592 | 593 | TEST_CASE("span element access") 594 | { 595 | constexpr int arr[] = {1, 2, 3}; 596 | span s{arr}; 597 | 598 | REQUIRE(s[0] == arr[0]); 599 | REQUIRE(s[1] == arr[1]); 600 | REQUIRE(s[2] == arr[2]); 601 | } 602 | 603 | TEST_CASE("span iterator support") 604 | { 605 | { 606 | std::vector vec; 607 | span s{vec}; 608 | std::sort(s.begin(), s.end()); 609 | REQUIRE(std::is_sorted(vec.cbegin(), vec.cend())); 610 | } 611 | 612 | { 613 | const std::vector vec{1, 2, 3}; 614 | span s{vec}; 615 | REQUIRE(std::equal(s.rbegin(), s.rend(), vec.crbegin())); 616 | } 617 | } 618 | 619 | TEST_CASE("make_span()") 620 | { 621 | { 622 | int arr[3] = {1, 2, 3}; 623 | auto s = tcb::make_span(arr); 624 | static_assert(std::is_same>::value, ""); 625 | REQUIRE(s.data() == arr); 626 | REQUIRE(s.size() == 3); 627 | } 628 | 629 | { 630 | const int arr[3] = {1, 2, 3}; 631 | auto s = tcb::make_span(arr); 632 | static_assert(std::is_same>::value, ""); 633 | REQUIRE(s.data() == arr); 634 | REQUIRE(s.size() == 3); 635 | } 636 | 637 | { 638 | std::array arr = {1, 2, 3}; 639 | auto s = tcb::make_span(arr); 640 | static_assert(std::is_same>::value, ""); 641 | REQUIRE(s.data() == arr.data()); 642 | REQUIRE(s.size() == arr.size()); 643 | } 644 | 645 | { 646 | const std::array arr = {1, 2, 3}; 647 | auto s = tcb::make_span(arr); 648 | static_assert(std::is_same>::value, ""); 649 | REQUIRE(s.data() == arr.data()); 650 | REQUIRE(s.size() == 3); 651 | } 652 | 653 | { 654 | std::array arr = {1, 2, 3}; 655 | auto s = tcb::make_span(arr); 656 | static_assert(std::is_same>::value, ""); 657 | REQUIRE(s.data() == arr.data()); 658 | REQUIRE(s.size() == 3); 659 | } 660 | 661 | { 662 | const std::array arr = {1, 2, 3}; 663 | auto s = tcb::make_span(arr); 664 | static_assert(std::is_same>::value, ""); 665 | REQUIRE(s.data() == arr.data()); 666 | REQUIRE(s.size() == 3); 667 | } 668 | 669 | { 670 | std::vector arr = {1, 2, 3}; 671 | auto s = tcb::make_span(arr); 672 | static_assert(std::is_same>::value, ""); 673 | REQUIRE(s.data() == arr.data()); 674 | REQUIRE(s.size() == arr.size()); 675 | } 676 | 677 | { 678 | const std::vector arr = {1, 2, 3}; 679 | auto s = tcb::make_span(arr); 680 | static_assert(std::is_same>::value, ""); 681 | REQUIRE(s.data() == arr.data()); 682 | REQUIRE(s.size() == arr.size()); 683 | } 684 | 685 | #ifdef TCB_SPAN_HAVE_CPP17 686 | { 687 | std::string_view str = "hello"; 688 | auto s = tcb::make_span(str); 689 | static_assert(std::is_same>::value, ""); 690 | REQUIRE(s.data() == str.data()); 691 | REQUIRE(s.size() == str.size()); 692 | } 693 | 694 | { 695 | const std::string_view str = "hello"; 696 | auto s = tcb::make_span(str); 697 | static_assert(std::is_same>::value, ""); 698 | REQUIRE(s.data() == str.data()); 699 | REQUIRE(s.size() == str.size()); 700 | } 701 | #endif // TCB_SPAN_HAVE_CPP17 702 | } 703 | -------------------------------------------------------------------------------- /test/test_structured_bindings.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "catch.hpp" 5 | 6 | using static_span_t = tcb::span; 7 | using dynamic_span_t = tcb::span; 8 | 9 | static_assert(std::tuple_size_v == static_span_t::extent); 10 | static_assert(!tcb::detail::is_complete>::value); 11 | 12 | TEST_CASE("Structured bindings") 13 | { 14 | // C++, why you no let me do constexpr structured bindings? 15 | 16 | int arr[] = {1, 2, 3}; 17 | 18 | auto& [a1, a2, a3] = arr; 19 | auto&& [s1, s2, s3] = tcb::make_span(arr); 20 | 21 | REQUIRE(a1 == s1); 22 | REQUIRE(a2 == s2); 23 | REQUIRE(a3 == s3); 24 | 25 | a1 = 99; 26 | REQUIRE(s1 == 99); 27 | 28 | s2 = 100; 29 | REQUIRE(a2 == 100); 30 | } 31 | --------------------------------------------------------------------------------