Added Guidelines Support Library (GSL)
This commit is contained in:
parent
7f72504448
commit
4662113254
|
@ -81,6 +81,9 @@ set_target_properties(gmock_main PROPERTIES FOLDER lib)
|
||||||
set_target_properties(gtest PROPERTIES FOLDER lib)
|
set_target_properties(gtest PROPERTIES FOLDER lib)
|
||||||
set_target_properties(gtest_main PROPERTIES FOLDER lib)
|
set_target_properties(gtest_main PROPERTIES FOLDER lib)
|
||||||
|
|
||||||
|
# ... GSL
|
||||||
|
include_directories(SYSTEM "lib/gsl/include")
|
||||||
|
|
||||||
# Define executable
|
# Define executable
|
||||||
include_directories("src" "src/audio_input")
|
include_directories("src" "src/audio_input")
|
||||||
configure_file(src/appInfo.cpp.in src/appInfo.cpp ESCAPE_QUOTES)
|
configure_file(src/appInfo.cpp.in src/appInfo.cpp ESCAPE_QUOTES)
|
||||||
|
|
15
LICENSE.md
15
LICENSE.md
|
@ -117,3 +117,18 @@ The [Google Test](https://github.com/google/googletest) framework is released un
|
||||||
> * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
> * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||||
>
|
>
|
||||||
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
### Guidelines Support Library (GSL)
|
||||||
|
|
||||||
|
The [Guidelines Support Library](https://github.com/Microsoft/GSL) is released under the **MIT License (MIT)**.
|
||||||
|
|
||||||
|
> Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
>
|
||||||
|
> This code is licensed under the MIT License (MIT).
|
||||||
|
>
|
||||||
|
> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
>
|
||||||
|
> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
>
|
||||||
|
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
>
|
|
@ -0,0 +1,21 @@
|
||||||
|
ColumnLimit: 100
|
||||||
|
|
||||||
|
UseTab: Never
|
||||||
|
IndentWidth: 4
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
NamespaceIndentation: Inner
|
||||||
|
|
||||||
|
BreakBeforeBraces: Allman
|
||||||
|
AlwaysBreakTemplateDeclarations: true
|
||||||
|
BreakConstructorInitializersBeforeComma: true
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: true
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
|
||||||
|
PointerAlignment: Left
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignTrailingComments: false
|
||||||
|
|
||||||
|
SpaceAfterCStyleCast: true
|
|
@ -0,0 +1,14 @@
|
||||||
|
tests/unittest-cpp
|
||||||
|
CMakeFiles
|
||||||
|
tests/CMakeFiles
|
||||||
|
tests/Debug
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
tests/*tests.dir
|
||||||
|
*.vcxproj
|
||||||
|
*.vcxproj.filters
|
||||||
|
*.sln
|
||||||
|
*.tlog
|
||||||
|
Testing/Temporary/*.*
|
||||||
|
CMakeCache.txt
|
||||||
|
*.suo
|
|
@ -0,0 +1,68 @@
|
||||||
|
# Based on https://github.com/ldionne/hana/blob/master/.travis.yml
|
||||||
|
|
||||||
|
language: cpp
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- env: COMPILER=clang++-3.6 BUILD_TYPE=Debug CLANG=1
|
||||||
|
compiler: clang
|
||||||
|
addons: &clang36
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- clang-3.6
|
||||||
|
- cmake
|
||||||
|
- g++-5
|
||||||
|
sources: &sources
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
- llvm-toolchain-precise-3.6
|
||||||
|
- kalakris-cmake
|
||||||
|
- env: COMPILER=clang++-3.6 BUILD_TYPE=Release CLANG=1
|
||||||
|
compiler: clang
|
||||||
|
addons: *clang36
|
||||||
|
- env: COMPILER=g++-5 BUILD_TYPE=Debug
|
||||||
|
compiler: gcc
|
||||||
|
addons: &gcc5
|
||||||
|
apt:
|
||||||
|
packages: g++-5
|
||||||
|
sources: *sources
|
||||||
|
- env: COMPILER=g++-5 BUILD_TYPE=Release
|
||||||
|
compiler: gcc
|
||||||
|
addons: *gcc5
|
||||||
|
|
||||||
|
install:
|
||||||
|
- which $COMPILER
|
||||||
|
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
|
||||||
|
- mkdir ${DEPS_DIR} && cd ${DEPS_DIR}
|
||||||
|
- |
|
||||||
|
if [[ "$CLANG" == 1 && "${TRAVIS_OS_NAME}" == "linux" && "${STDLIB}" != "libstdc++" ]]; then
|
||||||
|
if [[ "${COMPILER}" == "clang++-3.5" ]]; then LLVM_VERSION="3.5.2"; fi
|
||||||
|
if [[ "${COMPILER}" == "clang++-3.6" ]]; then LLVM_VERSION="3.6.2"; fi
|
||||||
|
if [[ "${COMPILER}" == "clang++-3.7" ]]; then LLVM_VERSION="3.7.0"; fi
|
||||||
|
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"
|
||||||
|
LIBCXXABI_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxxabi-${LLVM_VERSION}.src.tar.xz"
|
||||||
|
mkdir -p llvm llvm/build llvm/projects/libcxx llvm/projects/libcxxabi
|
||||||
|
travis_retry wget --quiet -O - ${LLVM_URL} | tar --strip-components=1 -xJ -C llvm
|
||||||
|
travis_retry wget --quiet -O - ${LIBCXX_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxx
|
||||||
|
travis_retry wget --quiet -O - ${LIBCXXABI_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxxabi
|
||||||
|
(cd llvm/build && cmake .. -DCMAKE_INSTALL_PREFIX=${DEPS_DIR}/llvm/install -DCMAKE_CXX_COMPILER=clang++)
|
||||||
|
(cd llvm/build/projects/libcxx && make install -j2)
|
||||||
|
(cd llvm/build/projects/libcxxabi && make install -j2)
|
||||||
|
export CXXFLAGS="-I ${DEPS_DIR}/llvm/install/include/c++/v1"
|
||||||
|
export LDFLAGS="-L ${DEPS_DIR}/llvm/install/lib -l c++ -l c++abi"
|
||||||
|
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${DEPS_DIR}/llvm/install/lib"
|
||||||
|
fi
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- cd ${TRAVIS_BUILD_DIR}
|
||||||
|
- git clone --depth 1 https://github.com/Microsoft/unittest-cpp tests/unittest-cpp
|
||||||
|
- cmake -H. -Bb -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_INSTALL_PREFIX=$PWD/o -DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||||
|
- cmake --build b
|
||||||
|
|
||||||
|
script:
|
||||||
|
- cd b
|
||||||
|
- ctest
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
|
@ -0,0 +1,11 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8.7)
|
||||||
|
|
||||||
|
project(GSL CXX)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
add_subdirectory(tests)
|
|
@ -0,0 +1,29 @@
|
||||||
|
## Contributing to the Guidelines Support Library
|
||||||
|
|
||||||
|
The Guidelines Support Library (GSL) contains functions and types that are suggested for use by the
|
||||||
|
[C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines). GSL design changes are made only as a result of modifications to the Guidelines.
|
||||||
|
|
||||||
|
GSL is accepting contributions that improve or refine any of the types in this library as well as ports to other platforms. Changes should have an issue
|
||||||
|
tracking the suggestion that has been approved by the maintainers. Your pull request should include a link to the bug that you are fixing. If you've submitted
|
||||||
|
a PR, please post a comment in the associated issue to avoid duplication of effort.
|
||||||
|
|
||||||
|
## Legal
|
||||||
|
You will need to complete a Contributor License Agreement (CLA). Briefly, this agreement testifies that you are granting us and the community permission to
|
||||||
|
use the submitted change according to the terms of the project's license, and that the work being submitted is under appropriate copyright.
|
||||||
|
|
||||||
|
Please submit a Contributor License Agreement (CLA) before submitting a pull request. You may visit https://cla.microsoft.com to sign digitally.
|
||||||
|
|
||||||
|
## Housekeeping
|
||||||
|
Your pull request should:
|
||||||
|
|
||||||
|
* Include a description of what your change intends to do
|
||||||
|
* Be a child commit of a reasonably recent commit in the **master** branch
|
||||||
|
* Requests need not be a single commit, but should be a linear sequence of commits (i.e. no merge commits in your PR)
|
||||||
|
* It is desirable, but not necessary, for the tests to pass at each commit. Please see [README.md](./README.md) for instructions to build the test suite.
|
||||||
|
* Have clear commit messages
|
||||||
|
* e.g. "Fix issue", "Add tests for type", etc.
|
||||||
|
* Include appropriate tests
|
||||||
|
* Tests should include reasonable permutations of the target fix/change
|
||||||
|
* Include baseline changes with your change
|
||||||
|
* All changed code must have 100% code coverage
|
||||||
|
* To avoid line ending issues, set `autocrlf = input` and `whitespace = cr-at-eol` in your git configuration
|
|
@ -0,0 +1,21 @@
|
||||||
|
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
|
||||||
|
This code is licensed under the MIT License (MIT).
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
|
@ -0,0 +1,67 @@
|
||||||
|
# GSL: Guidelines Support Library [![Build Status](https://travis-ci.org/Microsoft/GSL.svg?branch=master)](https://travis-ci.org/Microsoft/GSL) [![Build status](https://ci.appveyor.com/api/projects/status/github/Microsoft/GSL?svg=true)](https://ci.appveyor.com/project/neilmacintosh/GSL)
|
||||||
|
|
||||||
|
The Guidelines Support Library (GSL) contains functions and types that are suggested for use by the
|
||||||
|
[C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines) maintained by the [Standard C++ Foundation](https://isocpp.org).
|
||||||
|
This repo contains Microsoft's implementation of GSL.
|
||||||
|
|
||||||
|
The library includes types like `span<T>`, `string_span`, `owner<>` and others.
|
||||||
|
|
||||||
|
The entire implementation is provided inline in the headers under the [include](./include) directory. The implementation generally assumes a platform that implements C++14 support. There are specific workarounds to support MSVC 2013 and 2015.
|
||||||
|
|
||||||
|
While some types have been broken out into their own headers (e.g. [include/span.h](./include/span.h)),
|
||||||
|
it is simplest to just include [gsl.h](./include/gsl.h) and gain access to the entire library.
|
||||||
|
|
||||||
|
> NOTE: We encourage contributions that improve or refine any of the types in this library as well as ports to
|
||||||
|
other platforms. Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for more information about contributing.
|
||||||
|
|
||||||
|
# Quick Start
|
||||||
|
## Supported Platforms
|
||||||
|
The test suite that exercises GSL has been built and passes successfully on the following platforms:
|
||||||
|
|
||||||
|
* Windows using Visual Studio 2013
|
||||||
|
* Windows using Visual Studio 2015
|
||||||
|
* Windows using Clang/LLVM 3.6
|
||||||
|
* Windows using GCC 5.1
|
||||||
|
* GNU/Linux using Clang/LLVM 3.6
|
||||||
|
* GNU/Linux using GCC 5.1
|
||||||
|
* OS X Yosemite using Xcode with AppleClang 7.0.0.7000072
|
||||||
|
* OS X Yosemite using GCC-5.2.0
|
||||||
|
* FreeBSD 10.x with Clang/LLVM 3.6
|
||||||
|
|
||||||
|
> If you successfully port GSL to another platform, we would love to hear from you. Please submit an issue to let us know. Also please consider
|
||||||
|
contributing any changes that were necessary back to this project to benefit the wider community.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
These steps assume the source code of this repository has been cloned into a directory named `c:\GSL`.
|
||||||
|
|
||||||
|
1. Create a directory to contain the build outputs for a particular architecture (we name it c:\GSL\vs14-x86 in this example).
|
||||||
|
|
||||||
|
cd GSL
|
||||||
|
md build-x86
|
||||||
|
cd build-x86
|
||||||
|
|
||||||
|
2. Configure CMake to use the compiler of your choice (you can see a list by running `cmake --help`).
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
cmake --build . --config Debug
|
||||||
|
|
||||||
|
4. Run the test suite.
|
||||||
|
|
||||||
|
ctest -C Debug
|
||||||
|
|
||||||
|
All tests should pass - indicating your platform is fully supported and you are ready to use the GSL types!
|
||||||
|
|
||||||
|
## Using the libraries
|
||||||
|
As the types are entirely implemented inline in headers, there are no linking requirements.
|
||||||
|
|
||||||
|
Just place the contents of the [include](./include) directory within your source tree so it is available
|
||||||
|
to your compiler, then include the appropriate headers in your program, and away you go!
|
|
@ -0,0 +1,168 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef GSL_GSL_H
|
||||||
|
#define GSL_GSL_H
|
||||||
|
|
||||||
|
#include "gsl_assert.h" // Ensures/Expects
|
||||||
|
#include "gsl_util.h" // finally()/narrow()/narrow_cast()...
|
||||||
|
#include "span.h" // span, strided_span...
|
||||||
|
#include "string_span.h" // zstring, string_span, zstring_builder...
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
// No MSVC does constexpr fully yet
|
||||||
|
#pragma push_macro("constexpr")
|
||||||
|
#define constexpr
|
||||||
|
|
||||||
|
// MSVC 2013 workarounds
|
||||||
|
#if _MSC_VER <= 1800
|
||||||
|
// noexcept is not understood
|
||||||
|
#pragma push_macro("noexcept")
|
||||||
|
#define noexcept
|
||||||
|
|
||||||
|
// turn off some misguided warnings
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior
|
||||||
|
|
||||||
|
#endif // _MSC_VER <= 1800
|
||||||
|
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
|
||||||
|
namespace gsl
|
||||||
|
{
|
||||||
|
|
||||||
|
//
|
||||||
|
// GSL.owner: ownership pointers
|
||||||
|
//
|
||||||
|
using std::unique_ptr;
|
||||||
|
using std::shared_ptr;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
using owner = T;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// not_null
|
||||||
|
//
|
||||||
|
// Restricts a pointer or smart pointer to only hold non-null values.
|
||||||
|
//
|
||||||
|
// Has zero size overhead over T.
|
||||||
|
//
|
||||||
|
// If T is a pointer (i.e. T == U*) then
|
||||||
|
// - allow construction from U* or U&
|
||||||
|
// - disallow construction from nullptr_t
|
||||||
|
// - disallow default construction
|
||||||
|
// - ensure construction from U* fails with nullptr
|
||||||
|
// - allow implicit conversion to U*
|
||||||
|
//
|
||||||
|
template<class T>
|
||||||
|
class not_null
|
||||||
|
{
|
||||||
|
static_assert(std::is_assignable<T&, std::nullptr_t>::value, "T cannot be assigned nullptr.");
|
||||||
|
public:
|
||||||
|
not_null(T t) : ptr_(t) { ensure_invariant(); }
|
||||||
|
not_null& operator=(const T& t) { ptr_ = t; ensure_invariant(); return *this; }
|
||||||
|
|
||||||
|
not_null(const not_null &other) = default;
|
||||||
|
not_null& operator=(const not_null &other) = default;
|
||||||
|
|
||||||
|
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||||
|
not_null(const not_null<U> &other)
|
||||||
|
{
|
||||||
|
*this = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||||
|
not_null& operator=(const not_null<U> &other)
|
||||||
|
{
|
||||||
|
ptr_ = other.get();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prevents compilation when someone attempts to assign a nullptr
|
||||||
|
not_null(std::nullptr_t) = delete;
|
||||||
|
not_null(int) = delete;
|
||||||
|
not_null<T>& operator=(std::nullptr_t) = delete;
|
||||||
|
not_null<T>& operator=(int) = delete;
|
||||||
|
|
||||||
|
T get() const {
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
__assume(ptr_ != nullptr);
|
||||||
|
#endif
|
||||||
|
return ptr_;
|
||||||
|
} // the assume() should help the optimizer
|
||||||
|
|
||||||
|
operator T() const { return get(); }
|
||||||
|
T operator->() const { return get(); }
|
||||||
|
|
||||||
|
bool operator==(const T& rhs) const { return ptr_ == rhs; }
|
||||||
|
bool operator!=(const T& rhs) const { return !(*this == rhs); }
|
||||||
|
private:
|
||||||
|
T ptr_;
|
||||||
|
|
||||||
|
// we assume that the compiler can hoist/prove away most of the checks inlined from this function
|
||||||
|
// if not, we could make them optional via conditional compilation
|
||||||
|
void ensure_invariant() const { Expects(ptr_ != nullptr); }
|
||||||
|
|
||||||
|
// unwanted operators...pointers only point to single objects!
|
||||||
|
// TODO ensure all arithmetic ops on this type are unavailable
|
||||||
|
not_null<T>& operator++() = delete;
|
||||||
|
not_null<T>& operator--() = delete;
|
||||||
|
not_null<T> operator++(int) = delete;
|
||||||
|
not_null<T> operator--(int) = delete;
|
||||||
|
not_null<T>& operator+(size_t) = delete;
|
||||||
|
not_null<T>& operator+=(size_t) = delete;
|
||||||
|
not_null<T>& operator-(size_t) = delete;
|
||||||
|
not_null<T>& operator-=(size_t) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace gsl
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
template<class T>
|
||||||
|
struct hash<gsl::not_null<T>>
|
||||||
|
{
|
||||||
|
size_t operator()(const gsl::not_null<T> & value) const
|
||||||
|
{
|
||||||
|
return hash<T>{}(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#undef constexpr
|
||||||
|
#pragma pop_macro("constexpr")
|
||||||
|
|
||||||
|
#if _MSC_VER <= 1800
|
||||||
|
|
||||||
|
#undef noexcept
|
||||||
|
#pragma pop_macro("noexcept")
|
||||||
|
|
||||||
|
#pragma warning(pop)
|
||||||
|
|
||||||
|
#endif // _MSC_VER <= 1800
|
||||||
|
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#endif // GSL_GSL_H
|
|
@ -0,0 +1,78 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef GSL_CONTRACTS_H
|
||||||
|
#define GSL_CONTRACTS_H
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
//
|
||||||
|
// There are three configuration options for this GSL implementation's behavior
|
||||||
|
// when pre/post conditions on the GSL types are violated:
|
||||||
|
//
|
||||||
|
// 1. GSL_TERMINATE_ON_CONTRACT_VIOLATION: std::terminate will be called (default)
|
||||||
|
// 2. GSL_THROW_ON_CONTRACT_VIOLATION: a gsl::fail_fast exception will be thrown
|
||||||
|
// 3. GSL_UNENFORCED_ON_CONTRACT_VIOLATION: nothing happens
|
||||||
|
//
|
||||||
|
#if !(defined(GSL_THROW_ON_CONTRACT_VIOLATION) ^ defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) ^ defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION))
|
||||||
|
#define GSL_TERMINATE_ON_CONTRACT_VIOLATION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define GSL_STRINGIFY_DETAIL(x) #x
|
||||||
|
#define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x)
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// GSL.assert: assertions
|
||||||
|
//
|
||||||
|
|
||||||
|
#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace gsl
|
||||||
|
{
|
||||||
|
struct fail_fast : public std::runtime_error
|
||||||
|
{
|
||||||
|
explicit fail_fast(char const* const message) : std::runtime_error(message) {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#define Expects(cond) if (!(cond)) \
|
||||||
|
throw gsl::fail_fast("GSL: Precondition failure at " __FILE__ ": " GSL_STRINGIFY(__LINE__));
|
||||||
|
#define Ensures(cond) if (!(cond)) \
|
||||||
|
throw gsl::fail_fast("GSL: Postcondition failure at " __FILE__ ": " GSL_STRINGIFY(__LINE__));
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
|
||||||
|
|
||||||
|
|
||||||
|
#define Expects(cond) if (!(cond)) std::terminate();
|
||||||
|
#define Ensures(cond) if (!(cond)) std::terminate();
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION)
|
||||||
|
|
||||||
|
#define Expects(cond)
|
||||||
|
#define Ensures(cond)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // GSL_CONTRACTS_H
|
|
@ -0,0 +1,148 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef GSL_UTIL_H
|
||||||
|
#define GSL_UTIL_H
|
||||||
|
|
||||||
|
#include "gsl_assert.h" // Ensures/Expects
|
||||||
|
#include <array>
|
||||||
|
#include <utility>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
// No MSVC does constexpr fully yet
|
||||||
|
#pragma push_macro("constexpr")
|
||||||
|
#define constexpr
|
||||||
|
|
||||||
|
// MSVC 2013 workarounds
|
||||||
|
#if _MSC_VER <= 1800
|
||||||
|
// noexcept is not understood
|
||||||
|
#pragma push_macro("noexcept")
|
||||||
|
#define noexcept
|
||||||
|
|
||||||
|
// turn off some misguided warnings
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior
|
||||||
|
#pragma warning(disable: 4127) // conditional expression is constant
|
||||||
|
|
||||||
|
#endif // _MSC_VER <= 1800
|
||||||
|
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
|
||||||
|
namespace gsl
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// GSL.util: utilities
|
||||||
|
//
|
||||||
|
|
||||||
|
// final_act allows you to ensure something gets run at the end of a scope
|
||||||
|
template <class F>
|
||||||
|
class final_act
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit final_act(F f) noexcept
|
||||||
|
: f_(std::move(f)), invoke_(true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
final_act(final_act&& other) noexcept
|
||||||
|
: f_(std::move(other.f_)), invoke_(other.invoke_)
|
||||||
|
{ other.invoke_ = false; }
|
||||||
|
|
||||||
|
final_act(const final_act&) = delete;
|
||||||
|
final_act& operator=(const final_act&) = delete;
|
||||||
|
|
||||||
|
~final_act() noexcept { if (invoke_) f_(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
F f_;
|
||||||
|
bool invoke_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// finally() - convenience function to generate a final_act
|
||||||
|
template <class F>
|
||||||
|
inline final_act<F> finally(const F &f)
|
||||||
|
noexcept { return final_act<F>(f); }
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
inline final_act<F> finally(F &&f) noexcept
|
||||||
|
{ return final_act<F>(std::forward<F>(f)); }
|
||||||
|
|
||||||
|
// narrow_cast(): a searchable way to do narrowing casts of values
|
||||||
|
template<class T, class U>
|
||||||
|
inline constexpr T narrow_cast(U u) noexcept
|
||||||
|
{ return static_cast<T>(u); }
|
||||||
|
|
||||||
|
struct narrowing_error : public std::exception {};
|
||||||
|
|
||||||
|
namespace details
|
||||||
|
{
|
||||||
|
template<class T, class U>
|
||||||
|
struct is_same_signedness : public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value>
|
||||||
|
{};
|
||||||
|
}
|
||||||
|
|
||||||
|
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
|
||||||
|
template<class T, class U>
|
||||||
|
inline T narrow(U u)
|
||||||
|
{
|
||||||
|
T t = narrow_cast<T>(u);
|
||||||
|
if (static_cast<U>(t) != u)
|
||||||
|
throw narrowing_error();
|
||||||
|
if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))
|
||||||
|
throw narrowing_error();
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// at() - Bounds-checked way of accessing static arrays, std::array, std::vector
|
||||||
|
//
|
||||||
|
template <class T, size_t N>
|
||||||
|
constexpr T& at(T(&arr)[N], size_t index)
|
||||||
|
{ Expects(index < N); return arr[index]; }
|
||||||
|
|
||||||
|
template <class T, size_t N>
|
||||||
|
constexpr T& at(std::array<T, N>& arr, size_t index)
|
||||||
|
{ Expects(index < N); return arr[index]; }
|
||||||
|
|
||||||
|
template <class Cont>
|
||||||
|
constexpr typename Cont::value_type& at(Cont& cont, size_t index)
|
||||||
|
{ Expects(index < cont.size()); return cont[index]; }
|
||||||
|
|
||||||
|
} // namespace gsl
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#undef constexpr
|
||||||
|
#pragma pop_macro("constexpr")
|
||||||
|
|
||||||
|
#if _MSC_VER <= 1800
|
||||||
|
|
||||||
|
#undef noexcept
|
||||||
|
#pragma pop_macro("noexcept")
|
||||||
|
|
||||||
|
#pragma warning(pop)
|
||||||
|
|
||||||
|
#endif // _MSC_VER <= 1800
|
||||||
|
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#endif // GSL_UTIL_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,963 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef GSL_STRING_SPAN_H
|
||||||
|
#define GSL_STRING_SPAN_H
|
||||||
|
|
||||||
|
#include "gsl_assert.h"
|
||||||
|
#include "gsl_util.h"
|
||||||
|
#include "span.h"
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
// No MSVC does constexpr fully yet
|
||||||
|
#pragma push_macro("constexpr")
|
||||||
|
#define constexpr /* nothing */
|
||||||
|
|
||||||
|
// VS 2013 workarounds
|
||||||
|
#if _MSC_VER <= 1800
|
||||||
|
|
||||||
|
#define GSL_MSVC_HAS_TYPE_DEDUCTION_BUG
|
||||||
|
#define GSL_MSVC_HAS_SFINAE_SUBSTITUTION_ICE
|
||||||
|
#define GSL_MSVC_NO_CPP14_STD_EQUAL
|
||||||
|
#define GSL_MSVC_NO_DEFAULT_MOVE_CTOR
|
||||||
|
|
||||||
|
// noexcept is not understood
|
||||||
|
#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
|
||||||
|
#pragma push_macro("noexcept")
|
||||||
|
#define noexcept /* nothing */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _MSC_VER <= 1800
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
// In order to test the library, we need it to throw exceptions that we can catch
|
||||||
|
#ifdef GSL_THROW_ON_CONTRACT_VIOLATION
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma push_macro("noexcept")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define noexcept /* nothing */
|
||||||
|
|
||||||
|
#endif // GSL_THROW_ON_CONTRACT_VIOLATION
|
||||||
|
|
||||||
|
namespace gsl
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// czstring and wzstring
|
||||||
|
//
|
||||||
|
// These are "tag" typedef's for C-style strings (i.e. null-terminated character arrays)
|
||||||
|
// that allow static analysis to help find bugs.
|
||||||
|
//
|
||||||
|
// There are no additional features/semantics that we can find a way to add inside the
|
||||||
|
// type system for these types that will not either incur significant runtime costs or
|
||||||
|
// (sometimes needlessly) break existing programs when introduced.
|
||||||
|
//
|
||||||
|
|
||||||
|
template<typename CharT, std::ptrdiff_t Extent = dynamic_range>
|
||||||
|
using basic_zstring = CharT*;
|
||||||
|
|
||||||
|
template<std::ptrdiff_t Extent = dynamic_range>
|
||||||
|
using czstring = basic_zstring<const char, Extent>;
|
||||||
|
|
||||||
|
template<std::ptrdiff_t Extent = dynamic_range>
|
||||||
|
using cwzstring = basic_zstring<const wchar_t, Extent>;
|
||||||
|
|
||||||
|
template<std::ptrdiff_t Extent = dynamic_range>
|
||||||
|
using zstring = basic_zstring<char, Extent>;
|
||||||
|
|
||||||
|
template<std::ptrdiff_t Extent = dynamic_range>
|
||||||
|
using wzstring = basic_zstring<wchar_t, Extent>;
|
||||||
|
|
||||||
|
//
|
||||||
|
// ensure_sentinel()
|
||||||
|
//
|
||||||
|
// Provides a way to obtain an span from a contiguous sequence
|
||||||
|
// that ends with a (non-inclusive) sentinel value.
|
||||||
|
//
|
||||||
|
// Will fail-fast if sentinel cannot be found before max elements are examined.
|
||||||
|
//
|
||||||
|
template<typename T, const T Sentinel>
|
||||||
|
span<T, dynamic_range> ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX)
|
||||||
|
{
|
||||||
|
auto cur = seq;
|
||||||
|
while ((cur - seq) < max && *cur != Sentinel) ++cur;
|
||||||
|
Ensures(*cur == Sentinel);
|
||||||
|
return{ seq, cur - seq };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// ensure_z - creates a span for a czstring or cwzstring.
|
||||||
|
// Will fail fast if a null-terminator cannot be found before
|
||||||
|
// the limit of size_type.
|
||||||
|
//
|
||||||
|
template<typename T>
|
||||||
|
inline span<T, dynamic_range> ensure_z(T* const & sz, std::ptrdiff_t max = PTRDIFF_MAX)
|
||||||
|
{
|
||||||
|
return ensure_sentinel<T, 0>(sz, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO (neilmac) there is probably a better template-magic way to get the const and non-const overloads to share an implementation
|
||||||
|
inline span<char, dynamic_range> ensure_z(char* const& sz, std::ptrdiff_t max)
|
||||||
|
{
|
||||||
|
auto len = strnlen(sz, narrow_cast<size_t>(max));
|
||||||
|
Ensures(sz[len] == 0);
|
||||||
|
return{ sz, static_cast<std::ptrdiff_t>(len) };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline span<const char, dynamic_range> ensure_z(const char* const& sz, std::ptrdiff_t max)
|
||||||
|
{
|
||||||
|
auto len = strnlen(sz, narrow_cast<size_t>(max));
|
||||||
|
Ensures(sz[len] == 0);
|
||||||
|
return{ sz, static_cast<std::ptrdiff_t>(len) };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline span<wchar_t, dynamic_range> ensure_z(wchar_t* const& sz, std::ptrdiff_t max)
|
||||||
|
{
|
||||||
|
auto len = wcsnlen(sz, narrow_cast<size_t>(max));
|
||||||
|
Ensures(sz[len] == 0);
|
||||||
|
return{ sz, static_cast<std::ptrdiff_t>(len) };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline span<const wchar_t, dynamic_range> ensure_z(const wchar_t* const& sz, std::ptrdiff_t max)
|
||||||
|
{
|
||||||
|
auto len = wcsnlen(sz, narrow_cast<size_t>(max));
|
||||||
|
Ensures(sz[len] == 0);
|
||||||
|
return{ sz, static_cast<std::ptrdiff_t>(len) };
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, size_t N>
|
||||||
|
span<T, dynamic_range> ensure_z(T(&sz)[N]) { return ensure_z(&sz[0], static_cast<std::ptrdiff_t>(N)); }
|
||||||
|
|
||||||
|
template<class Cont>
|
||||||
|
span<typename std::remove_pointer<typename Cont::pointer>::type, dynamic_range> ensure_z(Cont& cont)
|
||||||
|
{
|
||||||
|
return ensure_z(cont.data(), static_cast<std::ptrdiff_t>(cont.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename CharT, std::ptrdiff_t>
|
||||||
|
class basic_string_span;
|
||||||
|
|
||||||
|
namespace details
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
struct is_basic_string_span_oracle : std::false_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent>
|
||||||
|
struct is_basic_string_span_oracle<basic_string_span<CharT, Extent>> : std::true_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_basic_string_span : is_basic_string_span_oracle<std::remove_cv_t<T>>
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct length_func
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct length_func<char>
|
||||||
|
{
|
||||||
|
std::ptrdiff_t operator()(char* const ptr, std::ptrdiff_t length) noexcept
|
||||||
|
{
|
||||||
|
return narrow_cast<std::ptrdiff_t>(strnlen(ptr, narrow_cast<size_t>(length)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct length_func<wchar_t>
|
||||||
|
{
|
||||||
|
std::ptrdiff_t operator()(wchar_t* const ptr, std::ptrdiff_t length) noexcept
|
||||||
|
{
|
||||||
|
return narrow_cast<std::ptrdiff_t>(wcsnlen(ptr, narrow_cast<size_t>(length)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct length_func<const char>
|
||||||
|
{
|
||||||
|
std::ptrdiff_t operator()(const char* const ptr, std::ptrdiff_t length) noexcept
|
||||||
|
{
|
||||||
|
return narrow_cast<std::ptrdiff_t>(strnlen(ptr, narrow_cast<size_t>(length)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct length_func<const wchar_t>
|
||||||
|
{
|
||||||
|
std::ptrdiff_t operator()(const wchar_t* const ptr, std::ptrdiff_t length) noexcept
|
||||||
|
{
|
||||||
|
return narrow_cast<std::ptrdiff_t>(wcsnlen(ptr, narrow_cast<size_t>(length)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// string_span and relatives
|
||||||
|
//
|
||||||
|
// Note that Extent is always single-dimension only
|
||||||
|
//
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = dynamic_range>
|
||||||
|
class basic_string_span
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = CharT;
|
||||||
|
using const_value_type = std::add_const_t<value_type>;
|
||||||
|
using pointer = std::add_pointer_t<value_type>;
|
||||||
|
using reference = std::add_lvalue_reference_t<value_type>;
|
||||||
|
using const_reference = std::add_lvalue_reference_t<const_value_type>;
|
||||||
|
using bounds_type = static_bounds<Extent>;
|
||||||
|
using impl_type = span<value_type, Extent>;
|
||||||
|
|
||||||
|
using size_type = ptrdiff_t;
|
||||||
|
using iterator = typename impl_type::iterator;
|
||||||
|
using const_iterator = typename impl_type::const_iterator;
|
||||||
|
using reverse_iterator = typename impl_type::reverse_iterator;
|
||||||
|
using const_reverse_iterator = typename impl_type::const_reverse_iterator;
|
||||||
|
|
||||||
|
// default (empty)
|
||||||
|
constexpr basic_string_span() = default;
|
||||||
|
|
||||||
|
// copy
|
||||||
|
constexpr basic_string_span(const basic_string_span& other) = default;
|
||||||
|
|
||||||
|
// move
|
||||||
|
#ifndef GSL_MSVC_NO_DEFAULT_MOVE_CTOR
|
||||||
|
constexpr basic_string_span(basic_string_span&& other) = default;
|
||||||
|
#else
|
||||||
|
constexpr basic_string_span(basic_string_span&& other)
|
||||||
|
: span_(std::move(other.span_))
|
||||||
|
{}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// assign
|
||||||
|
constexpr basic_string_span& operator=(const basic_string_span& other) = default;
|
||||||
|
|
||||||
|
// move assign
|
||||||
|
#ifndef GSL_MSVC_NO_DEFAULT_MOVE_CTOR
|
||||||
|
constexpr basic_string_span& operator=(basic_string_span&& other) = default;
|
||||||
|
#else
|
||||||
|
constexpr basic_string_span& operator=(basic_string_span&& other)
|
||||||
|
{
|
||||||
|
span_ = std::move(other.span_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// from nullptr
|
||||||
|
constexpr basic_string_span(std::nullptr_t ptr) noexcept
|
||||||
|
: span_(ptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// from nullptr and length
|
||||||
|
constexpr basic_string_span(std::nullptr_t ptr, size_type length) noexcept
|
||||||
|
: span_(ptr, length)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// From static arrays - if 0-terminated, remove 0 from the view
|
||||||
|
|
||||||
|
// from static arrays and string literals
|
||||||
|
template<size_t N>
|
||||||
|
constexpr basic_string_span(value_type(&arr)[N]) noexcept
|
||||||
|
: span_(remove_z(arr))
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Those allow 0s within the length, so we do not remove them
|
||||||
|
|
||||||
|
// from raw data and length
|
||||||
|
constexpr basic_string_span(pointer ptr, size_type length) noexcept
|
||||||
|
: span_(ptr, length)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// from string
|
||||||
|
constexpr basic_string_span(std::string& s) noexcept
|
||||||
|
: span_(const_cast<pointer>(s.data()), narrow_cast<std::ptrdiff_t>(s.length()))
|
||||||
|
{}
|
||||||
|
|
||||||
|
// from containers. Containers must have .size() and .data() function signatures
|
||||||
|
template <typename Cont, typename DataType = typename Cont::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<!details::is_span<Cont>::value
|
||||||
|
&& !details::is_basic_string_span<Cont>::value
|
||||||
|
&& !(!std::is_const<value_type>::value && std::is_const<Cont>::value) // no converting const containers to non-const span
|
||||||
|
&& std::is_convertible<DataType*, value_type*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<Cont>().size(), *std::declval<Cont>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
constexpr basic_string_span(Cont& cont)
|
||||||
|
: span_(cont.data(), cont.size())
|
||||||
|
{}
|
||||||
|
|
||||||
|
// disallow creation from temporary containers and strings
|
||||||
|
template <typename Cont, typename DataType = typename Cont::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<!details::is_span<Cont>::value
|
||||||
|
&& !details::is_basic_string_span<Cont>::value
|
||||||
|
&& std::is_convertible<DataType*, value_type*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<Cont>().size(), *std::declval<Cont>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
basic_string_span(Cont&& cont) = delete;
|
||||||
|
|
||||||
|
#ifndef GSL_MSVC_HAS_SFINAE_SUBSTITUTION_ICE
|
||||||
|
// from span
|
||||||
|
template <typename OtherValueType, std::ptrdiff_t OtherExtent,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
std::is_convertible<OtherValueType*, value_type*>::value
|
||||||
|
&& std::is_convertible<static_bounds<OtherExtent>, bounds_type>::value>
|
||||||
|
>
|
||||||
|
constexpr basic_string_span(span<OtherValueType, OtherExtent> other) noexcept
|
||||||
|
: span_(other)
|
||||||
|
{}
|
||||||
|
#else
|
||||||
|
// from span
|
||||||
|
constexpr basic_string_span(span<value_type, Extent> other) noexcept
|
||||||
|
: span_(other)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template <typename Dummy = std::enable_if_t<!std::is_same<std::remove_const_t<value_type>, value_type>::value>>
|
||||||
|
constexpr basic_string_span(span<std::remove_const_t<value_type>, Extent> other) noexcept
|
||||||
|
: span_(other)
|
||||||
|
{}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// from string_span
|
||||||
|
template <typename OtherValueType, std::ptrdiff_t OtherExtent,
|
||||||
|
typename OtherBounds = static_bounds<OtherExtent>,
|
||||||
|
typename Dummy = std::enable_if_t<std::is_convertible<OtherValueType*, value_type*>::value && std::is_convertible<OtherBounds, bounds_type>::value>
|
||||||
|
>
|
||||||
|
constexpr basic_string_span(basic_string_span<OtherValueType, OtherExtent> other) noexcept
|
||||||
|
: span_(other.data(), other.length())
|
||||||
|
{}
|
||||||
|
|
||||||
|
constexpr bool empty() const noexcept
|
||||||
|
{
|
||||||
|
return length() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// first Count elements
|
||||||
|
template<size_type Count>
|
||||||
|
constexpr basic_string_span<value_type, Count> first() const noexcept
|
||||||
|
{
|
||||||
|
return{ span_.template first<Count>() };
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr basic_string_span<value_type, dynamic_range> first(size_type count) const noexcept
|
||||||
|
{
|
||||||
|
return{ span_.first(count) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// last Count elements
|
||||||
|
template<size_type Count>
|
||||||
|
constexpr basic_string_span<value_type, Count> last() const noexcept
|
||||||
|
{
|
||||||
|
return{ span_.template last<Count>() };
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr basic_string_span<value_type, dynamic_range> last(size_type count) const noexcept
|
||||||
|
{
|
||||||
|
return{ span_.last(count) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a subview of Count elements starting from Offset
|
||||||
|
template<size_type Offset, size_type Count>
|
||||||
|
constexpr basic_string_span<value_type, Count> subspan() const noexcept
|
||||||
|
{
|
||||||
|
return{ span_.template subspan<Offset, Count>() };
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr basic_string_span<value_type, dynamic_range> subspan(size_type offset, size_type count = dynamic_range) const noexcept
|
||||||
|
{
|
||||||
|
return{ span_.subspan(offset, count) };
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr reference operator[](size_type idx) const noexcept
|
||||||
|
{
|
||||||
|
return span_[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr pointer data() const noexcept
|
||||||
|
{
|
||||||
|
return span_.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
// length of the span in elements
|
||||||
|
constexpr size_type length() const noexcept
|
||||||
|
{
|
||||||
|
return span_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// length of the span in elements
|
||||||
|
constexpr size_type size() const noexcept
|
||||||
|
{
|
||||||
|
return span_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// length of the span in bytes
|
||||||
|
constexpr size_type size_bytes() const noexcept
|
||||||
|
{
|
||||||
|
return span_.size_bytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// length of the span in bytes
|
||||||
|
constexpr size_type length_bytes() const noexcept
|
||||||
|
{
|
||||||
|
return span_.length_bytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr iterator begin() const noexcept
|
||||||
|
{
|
||||||
|
return span_.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr iterator end() const noexcept
|
||||||
|
{
|
||||||
|
return span_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const_iterator cbegin() const noexcept
|
||||||
|
{
|
||||||
|
return span_.cbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const_iterator cend() const noexcept
|
||||||
|
{
|
||||||
|
return span_.cend();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr reverse_iterator rbegin() const noexcept
|
||||||
|
{
|
||||||
|
return span_.rbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr reverse_iterator rend() const noexcept
|
||||||
|
{
|
||||||
|
return span_.rend();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const_reverse_iterator crbegin() const noexcept
|
||||||
|
{
|
||||||
|
return span_.crbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const_reverse_iterator crend() const noexcept
|
||||||
|
{
|
||||||
|
return span_.crend();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static impl_type remove_z(pointer const& sz, std::ptrdiff_t max) noexcept
|
||||||
|
{
|
||||||
|
return{ sz, details::length_func<value_type>()(sz, max)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
static impl_type remove_z(value_type(&sz)[N]) noexcept
|
||||||
|
{
|
||||||
|
return remove_z(&sz[0], narrow_cast<std::ptrdiff_t>(N));
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_type span_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<std::ptrdiff_t Extent = dynamic_range>
|
||||||
|
using string_span = basic_string_span<char, Extent>;
|
||||||
|
|
||||||
|
template<std::ptrdiff_t Extent = dynamic_range>
|
||||||
|
using cstring_span = basic_string_span<const char, Extent>;
|
||||||
|
|
||||||
|
template<std::ptrdiff_t Extent = dynamic_range>
|
||||||
|
using wstring_span = basic_string_span<wchar_t, Extent>;
|
||||||
|
|
||||||
|
template<std::ptrdiff_t Extent = dynamic_range>
|
||||||
|
using cwstring_span = basic_string_span<const wchar_t, Extent>;
|
||||||
|
|
||||||
|
//
|
||||||
|
// to_string() allow (explicit) conversions from string_span to string
|
||||||
|
//
|
||||||
|
#ifndef GSL_MSVC_HAS_TYPE_DEDUCTION_BUG
|
||||||
|
|
||||||
|
template<typename CharT, ptrdiff_t Extent>
|
||||||
|
std::basic_string<typename std::remove_const<CharT>::type> to_string(basic_string_span<CharT, Extent> view)
|
||||||
|
{
|
||||||
|
return{ view.data(), static_cast<size_t>(view.length()) };
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
inline std::string to_string(cstring_span<> view)
|
||||||
|
{
|
||||||
|
return{ view.data(), static_cast<size_t>(view.length()) };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string to_string(string_span<> view)
|
||||||
|
{
|
||||||
|
return{ view.data(), static_cast<size_t>(view.length()) };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::wstring to_string(cwstring_span<> view)
|
||||||
|
{
|
||||||
|
return{ view.data(), static_cast<size_t>(view.length()) };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::wstring to_string(wstring_span<> view)
|
||||||
|
{
|
||||||
|
return{ view.data(), static_cast<size_t>(view.length()) };
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// zero-terminated string span, used to convert
|
||||||
|
// zero-terminated spans to legacy strings
|
||||||
|
template<typename CharT, std::ptrdiff_t Extent = dynamic_range>
|
||||||
|
class basic_zstring_span
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = CharT;
|
||||||
|
using const_value_type = std::add_const_t<CharT>;
|
||||||
|
|
||||||
|
using pointer = std::add_pointer_t<value_type>;
|
||||||
|
using const_pointer = std::add_pointer_t<const_value_type>;
|
||||||
|
|
||||||
|
using zstring_type = basic_zstring<value_type, Extent>;
|
||||||
|
using const_zstring_type = basic_zstring<const_value_type, Extent>;
|
||||||
|
|
||||||
|
using impl_type = span<value_type, Extent>;
|
||||||
|
using string_span_type = basic_string_span<value_type, Extent>;
|
||||||
|
|
||||||
|
constexpr basic_zstring_span(impl_type span) noexcept
|
||||||
|
: span_(span)
|
||||||
|
{
|
||||||
|
// expects a zero-terminated span
|
||||||
|
Expects(span[span.size() - 1] == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy
|
||||||
|
constexpr basic_zstring_span(const basic_zstring_span& other) = default;
|
||||||
|
|
||||||
|
// move
|
||||||
|
#ifndef GSL_MSVC_NO_DEFAULT_MOVE_CTOR
|
||||||
|
constexpr basic_zstring_span(basic_zstring_span&& other) = default;
|
||||||
|
#else
|
||||||
|
constexpr basic_zstring_span(basic_zstring_span&& other)
|
||||||
|
: span_(std::move(other.span_))
|
||||||
|
{}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// assign
|
||||||
|
constexpr basic_zstring_span& operator=(const basic_zstring_span& other) = default;
|
||||||
|
|
||||||
|
// move assign
|
||||||
|
#ifndef GSL_MSVC_NO_DEFAULT_MOVE_CTOR
|
||||||
|
constexpr basic_zstring_span& operator=(basic_zstring_span&& other) = default;
|
||||||
|
#else
|
||||||
|
constexpr basic_zstring_span& operator=(basic_zstring_span&& other)
|
||||||
|
{
|
||||||
|
span_ = std::move(other.span_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
constexpr bool empty() const noexcept { return span_.size() == 0; }
|
||||||
|
|
||||||
|
constexpr string_span_type as_string_span() const noexcept { return span_.first(span_.size()-1); }
|
||||||
|
|
||||||
|
constexpr string_span_type ensure_z() const noexcept { return gsl::ensure_z(span_); }
|
||||||
|
|
||||||
|
constexpr const_zstring_type assume_z() const noexcept { return span_.data(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
impl_type span_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Max = dynamic_range>
|
||||||
|
using zstring_span = basic_zstring_span<char, Max>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Max = dynamic_range>
|
||||||
|
using wzstring_span = basic_zstring_span<wchar_t, Max>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Max = dynamic_range>
|
||||||
|
using czstring_span = basic_zstring_span<const char, Max>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Max = dynamic_range>
|
||||||
|
using cwzstring_span = basic_zstring_span<const wchar_t, Max>;
|
||||||
|
|
||||||
|
} // namespace GSL
|
||||||
|
|
||||||
|
// operator ==
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>
|
||||||
|
>
|
||||||
|
bool operator==(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept
|
||||||
|
{
|
||||||
|
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
|
||||||
|
#ifdef GSL_MSVC_NO_CPP14_STD_EQUAL
|
||||||
|
return (one.size() == tmp.size()) && std::equal(one.begin(), one.end(), tmp.begin());
|
||||||
|
#else
|
||||||
|
return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value>
|
||||||
|
>
|
||||||
|
bool operator==(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept
|
||||||
|
{
|
||||||
|
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
|
||||||
|
#ifdef GSL_MSVC_NO_CPP14_STD_EQUAL
|
||||||
|
return (tmp.size() == other.size()) && std::equal(tmp.begin(), tmp.end(), other.begin());
|
||||||
|
#else
|
||||||
|
return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
|
// so the cases below are already covered by the previous operators
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value
|
||||||
|
&& std::is_convertible<DataType*, CharT*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
bool operator==(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept
|
||||||
|
{
|
||||||
|
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
|
||||||
|
return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value
|
||||||
|
&& std::is_convertible<DataType*, CharT*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
bool operator==(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept
|
||||||
|
{
|
||||||
|
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
|
||||||
|
return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// operator !=
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>
|
||||||
|
>
|
||||||
|
bool operator!=(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept
|
||||||
|
{
|
||||||
|
return !(one == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value>
|
||||||
|
>
|
||||||
|
bool operator!=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept
|
||||||
|
{
|
||||||
|
return !(one == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
|
// so the cases below are already covered by the previous operators
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value
|
||||||
|
&& std::is_convertible<DataType*, CharT*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
bool operator!=(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept
|
||||||
|
{
|
||||||
|
return !(one == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value
|
||||||
|
&& std::is_convertible<DataType*, CharT*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
bool operator!=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept
|
||||||
|
{
|
||||||
|
return !(one == other);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// operator<
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>
|
||||||
|
>
|
||||||
|
bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept
|
||||||
|
{
|
||||||
|
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
|
||||||
|
return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value>
|
||||||
|
>
|
||||||
|
bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept
|
||||||
|
{
|
||||||
|
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
|
||||||
|
return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
|
// so the cases below are already covered by the previous operators
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value
|
||||||
|
&& std::is_convertible<DataType*, CharT*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept
|
||||||
|
{
|
||||||
|
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
|
||||||
|
return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value
|
||||||
|
&& std::is_convertible<DataType*, CharT*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept
|
||||||
|
{
|
||||||
|
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
|
||||||
|
return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// operator <=
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>
|
||||||
|
>
|
||||||
|
bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept
|
||||||
|
{
|
||||||
|
return !(other < one);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value>
|
||||||
|
>
|
||||||
|
bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept
|
||||||
|
{
|
||||||
|
return !(other < one);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
|
// so the cases below are already covered by the previous operators
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value
|
||||||
|
&& std::is_convertible<DataType*, CharT*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept
|
||||||
|
{
|
||||||
|
return !(other < one);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value
|
||||||
|
&& std::is_convertible<DataType*, CharT*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept
|
||||||
|
{
|
||||||
|
return !(other < one);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// operator>
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>
|
||||||
|
>
|
||||||
|
bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept
|
||||||
|
{
|
||||||
|
return other < one;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value>
|
||||||
|
>
|
||||||
|
bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept
|
||||||
|
{
|
||||||
|
return other < one;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
|
// so the cases below are already covered by the previous operators
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value
|
||||||
|
&& std::is_convertible<DataType*, CharT*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept
|
||||||
|
{
|
||||||
|
return other < one;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value
|
||||||
|
&& std::is_convertible<DataType*, CharT*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept
|
||||||
|
{
|
||||||
|
return other < one;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// operator >=
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>
|
||||||
|
>
|
||||||
|
bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept
|
||||||
|
{
|
||||||
|
return !(one < other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value>
|
||||||
|
>
|
||||||
|
bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept
|
||||||
|
{
|
||||||
|
return !(one < other);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
|
// so the cases below are already covered by the previous operators
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value
|
||||||
|
&& std::is_convertible<DataType*, CharT*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other) noexcept
|
||||||
|
{
|
||||||
|
return !(one < other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_range, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename Dummy = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value
|
||||||
|
&& !gsl::details::is_basic_string_span<T>::value
|
||||||
|
&& std::is_convertible<DataType*, CharT*>::value
|
||||||
|
&& std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>, DataType>::value>
|
||||||
|
>
|
||||||
|
bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other) noexcept
|
||||||
|
{
|
||||||
|
return !(one < other);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// VS 2013 workarounds
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#undef constexpr
|
||||||
|
#pragma pop_macro("constexpr")
|
||||||
|
|
||||||
|
#if _MSC_VER <= 1800
|
||||||
|
|
||||||
|
#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
|
||||||
|
#undef noexcept
|
||||||
|
#pragma pop_macro("noexcept")
|
||||||
|
#endif // GSL_THROW_ON_CONTRACT_VIOLATION
|
||||||
|
|
||||||
|
#undef GSL_MSVC_HAS_TYPE_DEDUCTION_BUG
|
||||||
|
#undef GSL_MSVC_HAS_SFINAE_SUBSTITUTION_ICE
|
||||||
|
#undef GSL_MSVC_NO_CPP14_STD_EQUAL
|
||||||
|
#undef GSL_MSVC_NO_DEFAULT_MOVE_CTOR
|
||||||
|
|
||||||
|
#endif // _MSC_VER <= 1800
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
|
||||||
|
|
||||||
|
#undef noexcept
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma pop_macro("noexcept")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // GSL_THROW_ON_CONTRACT_VIOLATION
|
||||||
|
#endif // GSL_STRING_SPAN_H
|
|
@ -0,0 +1,55 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8.7)
|
||||||
|
|
||||||
|
project(GSLTests CXX)
|
||||||
|
|
||||||
|
add_subdirectory(unittest-cpp)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
../include
|
||||||
|
./unittest-cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_definitions(-DGSL_THROW_ON_CONTRACT_VIOLATION)
|
||||||
|
|
||||||
|
if(MSVC14 OR MSVC12) # has the support we need
|
||||||
|
# remove unnecessary warnings about unchecked iterators
|
||||||
|
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
|
||||||
|
add_compile_options(/W4)
|
||||||
|
else()
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14)
|
||||||
|
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||||
|
if(COMPILER_SUPPORTS_CXX14)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -Wno-missing-braces")
|
||||||
|
elseif(COMPILER_SUPPORTS_CXX11)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wno-missing-braces")
|
||||||
|
else()
|
||||||
|
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/unittest-cpp)
|
||||||
|
message(FATAL_ERROR "Could not find unittest-cpp enlistment. Please run 'git clone https://github.com/Microsoft/unittest-cpp.git unittest-cpp' in the tests directory")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
function(add_gsl_test name)
|
||||||
|
add_executable(${name} ${name}.cpp ../include/gsl.h ../include/gsl_assert.h ../include/gsl_util.h ../include/span.h ../include/string_span.h)
|
||||||
|
target_link_libraries(${name} UnitTest++)
|
||||||
|
install(TARGETS ${name}
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
)
|
||||||
|
add_test(
|
||||||
|
${name}
|
||||||
|
${name}
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
add_gsl_test(span_tests)
|
||||||
|
add_gsl_test(strided_span_tests)
|
||||||
|
add_gsl_test(string_span_tests)
|
||||||
|
add_gsl_test(at_tests)
|
||||||
|
add_gsl_test(bounds_tests)
|
||||||
|
add_gsl_test(notnull_tests)
|
||||||
|
add_gsl_test(assertion_tests)
|
||||||
|
add_gsl_test(utils_tests)
|
||||||
|
add_gsl_test(owner_tests)
|
|
@ -0,0 +1,53 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <UnitTest++/UnitTest++.h>
|
||||||
|
#include <gsl.h>
|
||||||
|
|
||||||
|
using namespace gsl;
|
||||||
|
|
||||||
|
SUITE(assertion_tests)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, const char *[])
|
||||||
|
{
|
||||||
|
return UnitTest::RunAllTests();
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <UnitTest++/UnitTest++.h>
|
||||||
|
#include <gsl.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace gsl;
|
||||||
|
|
||||||
|
SUITE(at_tests)
|
||||||
|
{
|
||||||
|
TEST(static_array)
|
||||||
|
{
|
||||||
|
int a[] = { 1, 2, 3, 4 };
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
CHECK(at(a, i) == i+1);
|
||||||
|
|
||||||
|
CHECK_THROW(at(a, 4), fail_fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(std_array)
|
||||||
|
{
|
||||||
|
std::array<int,4> a = { 1, 2, 3, 4 };
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
CHECK(at(a, i) == i+1);
|
||||||
|
|
||||||
|
CHECK_THROW(at(a, 4), fail_fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StdVector)
|
||||||
|
{
|
||||||
|
std::vector<int> a = { 1, 2, 3, 4 };
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
CHECK(at(a, i) == i+1);
|
||||||
|
|
||||||
|
CHECK_THROW(at(a, 4), fail_fast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, const char *[])
|
||||||
|
{
|
||||||
|
return UnitTest::RunAllTests();
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <UnitTest++/UnitTest++.h>
|
||||||
|
#include <span.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace gsl;;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void use(std::ptrdiff_t&) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
SUITE(bounds_test)
|
||||||
|
{
|
||||||
|
TEST(basic_bounds)
|
||||||
|
{
|
||||||
|
for (auto point : static_bounds<dynamic_range, 3, 4 > { 2 })
|
||||||
|
{
|
||||||
|
for (decltype(point)::size_type j = 0;
|
||||||
|
j < static_cast<decltype(point)::size_type>(decltype(point)::rank);
|
||||||
|
j++)
|
||||||
|
{
|
||||||
|
use(j);
|
||||||
|
use(point[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(bounds_basic)
|
||||||
|
{
|
||||||
|
static_bounds<3, 4, 5> b;
|
||||||
|
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 };
|
||||||
|
|
||||||
|
auto itr = bounds.begin();
|
||||||
|
(void)itr;
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
span<int, 4, dynamic_range, 2> 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<dynamic_range, dynamic_range, dynamic_range> b3 = b1;
|
||||||
|
static_bounds<7, 4, 2> b4 = b3;
|
||||||
|
(void)b4;
|
||||||
|
|
||||||
|
static_bounds<dynamic_range> b11;
|
||||||
|
|
||||||
|
static_bounds<dynamic_range> 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();
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <UnitTest++/UnitTest++.h>
|
||||||
|
#include <gsl.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace gsl;
|
||||||
|
|
||||||
|
struct MyBase {};
|
||||||
|
struct MyDerived : public MyBase {};
|
||||||
|
struct Unrelated {};
|
||||||
|
|
||||||
|
// stand-in for a user-defined ref-counted class
|
||||||
|
template<typename T>
|
||||||
|
struct RefCounted
|
||||||
|
{
|
||||||
|
RefCounted(T* p) : p_(p) {}
|
||||||
|
operator T*() { return p_; }
|
||||||
|
T* p_;
|
||||||
|
};
|
||||||
|
|
||||||
|
SUITE(NotNullTests)
|
||||||
|
{
|
||||||
|
|
||||||
|
bool helper(not_null<int*> p)
|
||||||
|
{
|
||||||
|
return *p == 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestNotNullConstructors)
|
||||||
|
{
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
not_null<int*> p = nullptr; // yay...does not compile!
|
||||||
|
not_null<std::vector<char>*> p = 0; // yay...does not compile!
|
||||||
|
not_null<int*> p; // yay...does not compile!
|
||||||
|
std::unique_ptr<int> up = std::make_unique<int>(120);
|
||||||
|
not_null<int*> p = up;
|
||||||
|
|
||||||
|
// Forbid non-nullptr assignable types
|
||||||
|
not_null<std::vector<int>> f(std::vector<int>{1});
|
||||||
|
not_null<int> z(10);
|
||||||
|
not_null<std::vector<int>> y({1,2});
|
||||||
|
#endif
|
||||||
|
int i = 12;
|
||||||
|
auto rp = RefCounted<int>(&i);
|
||||||
|
not_null<int*> p(rp);
|
||||||
|
CHECK(p.get() == &i);
|
||||||
|
|
||||||
|
not_null<std::shared_ptr<int>> x(std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestNotNullCasting)
|
||||||
|
{
|
||||||
|
MyBase base;
|
||||||
|
MyDerived derived;
|
||||||
|
Unrelated unrelated;
|
||||||
|
not_null<Unrelated*> u = &unrelated;
|
||||||
|
(void)u;
|
||||||
|
not_null<MyDerived*> p = &derived;
|
||||||
|
not_null<MyBase*> 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<Unrelated*> r = p;
|
||||||
|
not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
|
||||||
|
#endif
|
||||||
|
not_null<Unrelated*> t = reinterpret_cast<Unrelated*>(p.get());
|
||||||
|
CHECK((void*)p.get() == (void*)t.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestNotNullAssignment)
|
||||||
|
{
|
||||||
|
int i = 12;
|
||||||
|
not_null<int*> p = &i;
|
||||||
|
CHECK(helper(p));
|
||||||
|
|
||||||
|
int* q = nullptr;
|
||||||
|
CHECK_THROW(p = q, fail_fast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, const char *[])
|
||||||
|
{
|
||||||
|
return UnitTest::RunAllTests();
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <UnitTest++/UnitTest++.h>
|
||||||
|
#include <gsl.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
using namespace gsl;
|
||||||
|
|
||||||
|
SUITE(owner_tests)
|
||||||
|
{
|
||||||
|
void f(int* i)
|
||||||
|
{
|
||||||
|
*i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(basic_test)
|
||||||
|
{
|
||||||
|
owner<int*> p = new int(120);
|
||||||
|
CHECK(*p == 120);
|
||||||
|
f(p);
|
||||||
|
CHECK(*p == 121);
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, const char *[])
|
||||||
|
{
|
||||||
|
return UnitTest::RunAllTests();
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,748 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <UnitTest++/UnitTest++.h>
|
||||||
|
#include <span.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace gsl;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct BaseClass {};
|
||||||
|
struct DerivedClass : BaseClass {};
|
||||||
|
}
|
||||||
|
|
||||||
|
SUITE(strided_span_tests)
|
||||||
|
{
|
||||||
|
TEST (span_section_test)
|
||||||
|
{
|
||||||
|
int a[30][4][5];
|
||||||
|
|
||||||
|
auto av = as_span(a);
|
||||||
|
auto sub = av.section({15, 0, 0}, gsl::index<3>{2, 2, 2});
|
||||||
|
auto subsub = sub.section({1, 0, 0}, gsl::index<3>{1, 1, 1});
|
||||||
|
(void)subsub;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(span_section)
|
||||||
|
{
|
||||||
|
std::vector<int> data(5 * 10);
|
||||||
|
std::iota(begin(data), end(data), 0);
|
||||||
|
const span<int, 5, 10> av = as_span(span<int>{data}, dim<5>(), dim<10>());
|
||||||
|
|
||||||
|
strided_span<int, 2> 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));
|
||||||
|
|
||||||
|
strided_span<int, 2> 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
|
||||||
|
{
|
||||||
|
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<int, 1> 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<const int, 1> 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<int, 2> 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 span constructor
|
||||||
|
{
|
||||||
|
int arr[] = { 1, 2 };
|
||||||
|
|
||||||
|
// From non-cv-qualified source
|
||||||
|
{
|
||||||
|
const span<int> src = arr;
|
||||||
|
|
||||||
|
strided_span<int, 1> 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<const int, 1> sav_c{ {src}, {2, 1} };
|
||||||
|
strided_span<const int, 1> sav_c{ span<const int>{src}, strided_bounds<1>{2, 1} };
|
||||||
|
#else
|
||||||
|
strided_span<const int, 1> sav_c{ span<const int>{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<volatile int, 1> sav_v{ src, {2, 1} };
|
||||||
|
#else
|
||||||
|
strided_span<volatile int, 1> sav_v{ span<volatile int>{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<const volatile int, 1> sav_cv{ src, {2, 1} };
|
||||||
|
#else
|
||||||
|
strided_span<const volatile int, 1> sav_cv{ span<const volatile int>{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 span<const int> src{ arr };
|
||||||
|
|
||||||
|
strided_span<const int, 1> 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<const volatile int, 1> sav_cv{ src, {2, 1} };
|
||||||
|
#else
|
||||||
|
strided_span<const volatile int, 1> sav_cv{ span<const volatile int>{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 span<volatile int> src{ arr };
|
||||||
|
|
||||||
|
strided_span<volatile int, 1> 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<const volatile int, 1> sav_cv{ src, {2, 1} };
|
||||||
|
#else
|
||||||
|
strided_span<const volatile int, 1> sav_cv{ span<const volatile int>{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 span<const volatile int> src{ arr };
|
||||||
|
|
||||||
|
strided_span<const volatile int, 1> 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 span<int, 2> av(arr, 2);
|
||||||
|
span<const int, 2> av2{ av };
|
||||||
|
CHECK(av2[1] == 5);
|
||||||
|
|
||||||
|
static_assert(std::is_convertible<const span<int, 2>, span<const int, 2>>::value, "ctor is not implicit!");
|
||||||
|
|
||||||
|
const strided_span<int, 1> src{ arr, {2, 1} };
|
||||||
|
strided_span<const int, 1> sav{ src };
|
||||||
|
CHECK(sav.bounds().index_bounds() == index<1>{ 2 });
|
||||||
|
CHECK(sav.bounds().stride() == 1);
|
||||||
|
CHECK(sav[1] == 5);
|
||||||
|
|
||||||
|
static_assert(std::is_convertible<const strided_span<int, 1>, strided_span<const int, 1>>::value, "ctor is not implicit!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check copy constructor
|
||||||
|
{
|
||||||
|
int arr1[2] = { 3, 4 };
|
||||||
|
const strided_span<int, 1> src1{ arr1, {2, 1} };
|
||||||
|
strided_span<int, 1> 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<const int, 2> src2{ arr2, {{ 3, 2 }, { 2, 1 }} };
|
||||||
|
strided_span<const int, 2> 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<int, 1> src{ arr1, {{2}, {1}} };
|
||||||
|
strided_span<const int, 1> sav{ arr2, {{3}, {2}} };
|
||||||
|
strided_span<const int, 1>& 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<int, 1> src1{ arr1, {2, 1} };
|
||||||
|
strided_span<int, 1> sav1{ arr1b, {1, 1} };
|
||||||
|
strided_span<int, 1>& 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<const int, 2> src2{ arr2, {{ 3, 2 },{ 2, 1 }} };
|
||||||
|
strided_span<const int, 2> sav2{ arr2b, {{ 1, 1 },{ 1, 1 }} };
|
||||||
|
strided_span<const int, 2>& 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<int> data(5 * 10);
|
||||||
|
std::iota(begin(data), end(data), 0);
|
||||||
|
const span<int, 5, 10> src = as_span(span<int>{data}, dim<5>(), dim<10>());
|
||||||
|
|
||||||
|
const strided_span<int, 2> sav{ src, {{5, 10}, {10, 1}} };
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
const strided_span<const int, 2> csav{ {src},{ { 5, 10 },{ 10, 1 } } };
|
||||||
|
#endif
|
||||||
|
const strided_span<const int, 2> csav{ span<const int, 5, 10>{ src }, { { 5, 10 },{ 10, 1 } } };
|
||||||
|
|
||||||
|
strided_span<int, 1> sav_sl = sav[2];
|
||||||
|
CHECK(sav_sl[0] == 20);
|
||||||
|
CHECK(sav_sl[9] == 29);
|
||||||
|
|
||||||
|
strided_span<const int, 1> 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<int, 2> 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<int, 1> cm_sl = cm_sav[3];
|
||||||
|
|
||||||
|
CHECK(cm_sl[0] == 10);
|
||||||
|
CHECK(cm_sl[1] == 11);
|
||||||
|
CHECK(cm_sl[2] == 12);
|
||||||
|
|
||||||
|
// Section
|
||||||
|
strided_span<int, 2> 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 };
|
||||||
|
span<int> 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<int, 1> sav{ av,{ { 4 },{} } };
|
||||||
|
CHECK(sav[0] == 0);
|
||||||
|
CHECK(sav[3] == 0);
|
||||||
|
CHECK_THROW(sav[4], fail_fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// zero extent
|
||||||
|
strided_span<int, 1> sav{ av,{ {},{ 1 } } };
|
||||||
|
CHECK_THROW(sav[0], fail_fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// zero extent and stride
|
||||||
|
strided_span<int, 1> sav{ av,{ {},{} } };
|
||||||
|
CHECK_THROW(sav[0], fail_fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// strided array ctor with matching strided bounds
|
||||||
|
strided_span<int, 1> 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<int, 1> 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<int, 1> 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<int, 1> { arr, { 3, 2 } }), fail_fast);
|
||||||
|
CHECK_THROW((strided_span<int, 1> { arr, { 3, 3 } }), fail_fast);
|
||||||
|
CHECK_THROW((strided_span<int, 1> { arr, { 4, 5 } }), fail_fast);
|
||||||
|
CHECK_THROW((strided_span<int, 1> { arr, { 5, 1 } }), fail_fast);
|
||||||
|
CHECK_THROW((strided_span<int, 1> { arr, { 5, 5 } }), fail_fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// bounds cross data boundaries - from array view
|
||||||
|
CHECK_THROW((strided_span<int, 1> { av, { 3, 2 } }), fail_fast);
|
||||||
|
CHECK_THROW((strided_span<int, 1> { av, { 3, 3 } }), fail_fast);
|
||||||
|
CHECK_THROW((strided_span<int, 1> { av, { 4, 5 } }), fail_fast);
|
||||||
|
CHECK_THROW((strided_span<int, 1> { av, { 5, 1 } }), fail_fast);
|
||||||
|
CHECK_THROW((strided_span<int, 1> { av, { 5, 5 } }), fail_fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// bounds cross data boundaries - from dynamic arrays
|
||||||
|
CHECK_THROW((strided_span<int, 1> { av.data(), 4, { 3, 2 } }), fail_fast);
|
||||||
|
CHECK_THROW((strided_span<int, 1> { av.data(), 4, { 3, 3 } }), fail_fast);
|
||||||
|
CHECK_THROW((strided_span<int, 1> { av.data(), 4, { 4, 5 } }), fail_fast);
|
||||||
|
CHECK_THROW((strided_span<int, 1> { av.data(), 4, { 5, 1 } }), fail_fast);
|
||||||
|
CHECK_THROW((strided_span<int, 1> { av.data(), 4, { 5, 5 } }), fail_fast);
|
||||||
|
CHECK_THROW((strided_span<int, 1> { av.data(), 2, { 2, 2 } }), fail_fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
{
|
||||||
|
strided_span<int, 1> sav0{ av.data(), { 3, 2 } };
|
||||||
|
strided_span<int, 1> sav1{ arr, { 1 } };
|
||||||
|
strided_span<int, 1> sav2{ arr, { 1,1,1 } };
|
||||||
|
strided_span<int, 1> sav3{ av, { 1 } };
|
||||||
|
strided_span<int, 1> sav4{ av, { 1,1,1 } };
|
||||||
|
strided_span<int, 2> sav5{ av.as_span(dim<2>(), dim<2>()), { 1 } };
|
||||||
|
strided_span<int, 2> sav6{ av.as_span(dim<2>(), dim<2>()), { 1,1,1 } };
|
||||||
|
strided_span<int, 2> sav7{ av.as_span(dim<2>(), dim<2>()), { { 1,1 },{ 1,1 },{ 1,1 } } };
|
||||||
|
|
||||||
|
index<1> index{ 0, 1 };
|
||||||
|
strided_span<int, 1> sav8{ arr,{ 1,{ 1,1 } } };
|
||||||
|
strided_span<int, 1> sav9{ arr,{ { 1,1 },{ 1,1 } } };
|
||||||
|
strided_span<int, 1> sav10{ av,{ 1,{ 1,1 } } };
|
||||||
|
strided_span<int, 1> sav11{ av,{ { 1,1 },{ 1,1 } } };
|
||||||
|
strided_span<int, 2> sav12{ av.as_span(dim<2>(), dim<2>()),{ { 1 },{ 1 } } };
|
||||||
|
strided_span<int, 2> sav13{ av.as_span(dim<2>(), dim<2>()),{ { 1 },{ 1,1,1 } } };
|
||||||
|
strided_span<int, 2> sav14{ av.as_span(dim<2>(), dim<2>()),{ { 1,1,1 },{ 1 } } };
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(strided_span_type_conversion)
|
||||||
|
{
|
||||||
|
int arr[] = { 0, 1, 2, 3 };
|
||||||
|
span<int> av(arr);
|
||||||
|
|
||||||
|
{
|
||||||
|
strided_span<int, 1> sav{ av.data(), av.size(), { av.size() / 2, 2 } };
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
strided_span<long, 1> lsav1 = sav.as_strided_span<long, 1>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
{
|
||||||
|
strided_span<int, 1> sav{ av, { av.size() / 2, 2 } };
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
strided_span<long, 1> lsav1 = sav.as_strided_span<long, 1>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
span<const byte, dynamic_range> 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<const byte, 2> sav2{ bytes.data(), bytes.size(), bounds };
|
||||||
|
strided_span<const int, 2> sav3 = sav2.as_strided_span<const int>();
|
||||||
|
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 span
|
||||||
|
{
|
||||||
|
strided_bounds<2> bounds{ { 2, bytes.size() / 4 }, { bytes.size() / 2, 1 } };
|
||||||
|
span<const byte, 2, dynamic_range> bytes2 = as_span(bytes, dim<2>(), dim<>(bytes.size() / 2));
|
||||||
|
strided_span<const byte, 2> sav2{ bytes2, bounds };
|
||||||
|
strided_span<int, 2> sav3 = sav2.as_strided_span<int>();
|
||||||
|
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 } };
|
||||||
|
span<const byte, 2, dynamic_range> bytes2 = as_span(bytes, dim<2>(), dim<>(bytes.size() / 2));
|
||||||
|
strided_span<const byte, 2> sav2{ bytes2, bounds };
|
||||||
|
CHECK_THROW(sav2.as_strided_span<int>(), fail_fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
// retype strided array with not enough elements - strides are too small
|
||||||
|
{
|
||||||
|
strided_bounds<2> bounds{ { 4,2 },{ 2, 1 } };
|
||||||
|
span<const byte, 2, dynamic_range> bytes2 = as_span(bytes, dim<2>(), dim<>(bytes.size() / 2));
|
||||||
|
strided_span<const byte, 2> sav2{ bytes2, bounds };
|
||||||
|
CHECK_THROW(sav2.as_strided_span<int>(), 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 } };
|
||||||
|
span<const byte, 2, dynamic_range> bytes2 = as_span(bytes, dim<2>(), dim<>(bytes.size() / 2));
|
||||||
|
strided_span<const byte, 2> sav2{ bytes2, bounds };
|
||||||
|
CHECK_THROW(sav2.as_strided_span<int>(), 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 } };
|
||||||
|
span<const byte, 2, dynamic_range> bytes2 = as_span(bytes, dim<2>(), dim<>(bytes.size() / 2));
|
||||||
|
strided_span<const byte, 2> sav2{ bytes2, bounds };
|
||||||
|
CHECK_THROW(sav2.as_strided_span<int>(), fail_fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
// retype strided array with irregular strides - from raw data
|
||||||
|
{
|
||||||
|
strided_bounds<1> bounds{ bytes.size() / 2, 2 };
|
||||||
|
strided_span<const byte, 1> sav2{ bytes.data(), bytes.size(), bounds };
|
||||||
|
CHECK_THROW(sav2.as_strided_span<int>(), fail_fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
// retype strided array with irregular strides - from span
|
||||||
|
{
|
||||||
|
strided_bounds<1> bounds{ bytes.size() / 2, 2 };
|
||||||
|
strided_span<const byte, 1> sav2{ bytes, bounds };
|
||||||
|
CHECK_THROW(sav2.as_strided_span<int>(), fail_fast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(empty_strided_spans)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
span<int, 0> empty_av(nullptr);
|
||||||
|
strided_span<int, 1> 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 (auto& v : empty_sav)
|
||||||
|
{
|
||||||
|
(void)v;
|
||||||
|
CHECK(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
strided_span<int, 1> 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 (auto& v : empty_sav)
|
||||||
|
{
|
||||||
|
(void)v;
|
||||||
|
CHECK(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void iterate_every_other_element(span<int, dynamic_range> 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<int, 1> 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(strided_span_section_iteration)
|
||||||
|
{
|
||||||
|
int arr[8] = {4,0,5,1,6,2,7,3};
|
||||||
|
|
||||||
|
// static bounds
|
||||||
|
{
|
||||||
|
span<int, 8> av(arr, 8);
|
||||||
|
iterate_every_other_element(av);
|
||||||
|
}
|
||||||
|
|
||||||
|
// dynamic bounds
|
||||||
|
{
|
||||||
|
span<int, dynamic_range> av(arr, 8);
|
||||||
|
iterate_every_other_element(av);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto av = as_span(arr, 8);
|
||||||
|
iterate_every_other_element(av);
|
||||||
|
|
||||||
|
delete[] arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iterate_second_slice(span<int, dynamic_range, dynamic_range, dynamic_range> av)
|
||||||
|
{
|
||||||
|
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 (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
span<int, 3, 4, 2> av = arr;
|
||||||
|
iterate_second_slice(av);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(dynamic_strided_span_section_iteration_3d)
|
||||||
|
{
|
||||||
|
auto height = 12, width = 2;
|
||||||
|
auto size = height * width;
|
||||||
|
|
||||||
|
auto arr = new int[size];
|
||||||
|
for (auto i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
arr[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto av = as_span(as_span(arr, 24), dim<3>(), dim<4>(), dim<2>());
|
||||||
|
iterate_second_slice(av);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto av = as_span(as_span(arr, 24), dim<>(3), dim<4>(), dim<2>());
|
||||||
|
iterate_second_slice(av);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto av = as_span(as_span(arr, 24), dim<3>(), dim<>(4), dim<2>());
|
||||||
|
iterate_second_slice(av);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto av = as_span(as_span(arr, 24), dim<3>(), dim<4>(), dim<>(2));
|
||||||
|
iterate_second_slice(av);
|
||||||
|
}
|
||||||
|
delete[] arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(strided_span_conversion)
|
||||||
|
{
|
||||||
|
// get an 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 = sizeof(int) * 12 / d2;
|
||||||
|
|
||||||
|
// convert to 4x12 array of bytes
|
||||||
|
auto av = as_span(as_bytes(as_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<int>(); // { { 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<int, 2> transposed{cs.data(), cs.bounds().total_size(), reverse_bounds};
|
||||||
|
|
||||||
|
// slice to get a one-dimensional array of c's
|
||||||
|
strided_span<int, 1> 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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, const char *[])
|
||||||
|
{
|
||||||
|
return UnitTest::RunAllTests();
|
||||||
|
}
|
|
@ -0,0 +1,952 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <UnitTest++/UnitTest++.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <string_span.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace gsl;
|
||||||
|
|
||||||
|
|
||||||
|
SUITE(string_span_tests)
|
||||||
|
{
|
||||||
|
|
||||||
|
TEST(TestLiteralConstruction)
|
||||||
|
{
|
||||||
|
cwstring_span<> v = ensure_z(L"Hello");
|
||||||
|
CHECK(5 == v.length());
|
||||||
|
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
wstring_span<> v2 = ensure0(L"Hello");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestConstructFromStdString)
|
||||||
|
{
|
||||||
|
std::string s = "Hello there world";
|
||||||
|
cstring_span<> v = s;
|
||||||
|
CHECK(v.length() == static_cast<cstring_span<>::size_type>(s.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestConstructFromStdVector)
|
||||||
|
{
|
||||||
|
std::vector<char> vec(5, 'h');
|
||||||
|
string_span<> v = vec;
|
||||||
|
CHECK(v.length() == static_cast<string_span<>::size_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);
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(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<cstring_span<>::size_type>(s2.length()) == v.length());
|
||||||
|
CHECK(s2.length() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EqualityAndImplicitConstructors)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
cstring_span<> span = "Hello";
|
||||||
|
cstring_span<> span1;
|
||||||
|
|
||||||
|
// comparison to empty span
|
||||||
|
CHECK(span1 != span);
|
||||||
|
CHECK(span != span1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
cstring_span<> span = "Hello";
|
||||||
|
cstring_span<> span1 = "Hello1";
|
||||||
|
|
||||||
|
// comparison to different span
|
||||||
|
CHECK(span1 != span);
|
||||||
|
CHECK(span != span1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
gsl::span<const char> sp = ensure_z("Hello");
|
||||||
|
|
||||||
|
// comparison to literal
|
||||||
|
CHECK(span == cstring_span<>("Hello"));
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
// 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<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
gsl::span<char> 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<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
gsl::span<const char> 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<char> _vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
gsl::span<char> _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<char> str1 = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
cstring_span<> span1 = str1;
|
||||||
|
std::vector<char> str2 = std::move(str1);
|
||||||
|
cstring_span<> span2 = str2;
|
||||||
|
|
||||||
|
// comparison of spans from the same vector before and after move (ok)
|
||||||
|
CHECK(span1 == span2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(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<char> 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<char> 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
|
||||||
|
{
|
||||||
|
char* 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(Constructors)
|
||||||
|
{
|
||||||
|
// creating cstring_span
|
||||||
|
|
||||||
|
// from span of a final extent
|
||||||
|
{
|
||||||
|
span<const char, 6> 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<const char, 6> sp = "Hello";
|
||||||
|
string_span<> span = sp;
|
||||||
|
CHECK(span.length() == 6);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// from string temporary
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
{
|
||||||
|
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";
|
||||||
|
cstring_span<> span = str;
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// from non-const string
|
||||||
|
{
|
||||||
|
std::string str = "Hello";
|
||||||
|
cstring_span<> span = str;
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// from const vector
|
||||||
|
{
|
||||||
|
const std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
cstring_span<> span = vec;
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// from non-const vector
|
||||||
|
{
|
||||||
|
std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
cstring_span<> span = vec;
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// from const span
|
||||||
|
{
|
||||||
|
std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
const span<const char> inner = vec;
|
||||||
|
cstring_span<> span = inner;
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// from non-const span
|
||||||
|
{
|
||||||
|
std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
span<char> inner = vec;
|
||||||
|
cstring_span<> span = inner;
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// from const string_span
|
||||||
|
{
|
||||||
|
std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
cstring_span<> tmp = vec;
|
||||||
|
cstring_span<> span = tmp;
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// from non-const string_span
|
||||||
|
{
|
||||||
|
std::vector<char> 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<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
string_span<> span = vec;
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// from non-const vector
|
||||||
|
{
|
||||||
|
std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
string_span<> span = vec;
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// from const span
|
||||||
|
{
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
const span<const char> inner = vec;
|
||||||
|
string_span<> span = inner;
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// from non-const span
|
||||||
|
{
|
||||||
|
std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
span<char> 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<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
const span<char> inner = vec;
|
||||||
|
string_span<> span = inner;
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// from const string_span
|
||||||
|
{
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
std::vector<char> 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<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
string_span<> tmp = vec;
|
||||||
|
string_span<> span = tmp;
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// from non-const string_span from const vector
|
||||||
|
{
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
const std::vector<char> 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<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
const string_span<> tmp = vec;
|
||||||
|
string_span<> span = tmp;
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T move_wrapper(T&& t)
|
||||||
|
{
|
||||||
|
return std::move(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T create() { return T{}; }
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void use(basic_string_span<T, gsl::dynamic_range> s) {}
|
||||||
|
|
||||||
|
TEST(MoveConstructors)
|
||||||
|
{
|
||||||
|
// move string_span
|
||||||
|
{
|
||||||
|
cstring_span<> span = "Hello";
|
||||||
|
auto span1 = std::move(span);
|
||||||
|
CHECK(span1.length() == 5);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
cstring_span<> span = "Hello";
|
||||||
|
auto span1 = move_wrapper(std::move(span));
|
||||||
|
CHECK(span1.length() == 5);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
cstring_span<> span = "Hello";
|
||||||
|
auto span1 = move_wrapper(std::move(span));
|
||||||
|
CHECK(span1.length() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// move span
|
||||||
|
{
|
||||||
|
span<const char> span = ensure_z("Hello");
|
||||||
|
cstring_span<> span1 = std::move(span);
|
||||||
|
CHECK(span1.length() == 5);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
span<const char> span = ensure_z("Hello");
|
||||||
|
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::string>(std::move(str));
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
{
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
use<char>(create<string>());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// move container
|
||||||
|
{
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
string_span<> span = std::move(vec);
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
{
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
|
||||||
|
string_span<> span = move_wrapper<std::vector<char>>(std::move(vec));
|
||||||
|
CHECK(span.length() == 5);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
{
|
||||||
|
#ifdef CONFIRM_COMPILATION_ERRORS
|
||||||
|
use<char>(create<std::vector<char>>());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(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(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_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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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(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';
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
auto name = CreateTempNameW({ buf, 10 });
|
||||||
|
if (!name.empty())
|
||||||
|
{
|
||||||
|
cwzstring<> str = name.assume_z();
|
||||||
|
CHECK(wcsnlen(str, 10) == 3);
|
||||||
|
CHECK(*(str + 3) == L'\0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, const char *[])
|
||||||
|
{
|
||||||
|
return UnitTest::RunAllTests();
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <UnitTest++/UnitTest++.h>
|
||||||
|
#include <gsl.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
using namespace gsl;
|
||||||
|
|
||||||
|
SUITE(utils_tests)
|
||||||
|
{
|
||||||
|
void f(int& i)
|
||||||
|
{
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(finally_lambda)
|
||||||
|
{
|
||||||
|
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<char>(n);
|
||||||
|
CHECK(c == 120);
|
||||||
|
|
||||||
|
n = 300;
|
||||||
|
unsigned char uc = narrow_cast<unsigned char>(n);
|
||||||
|
CHECK(uc == 44);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(narrow)
|
||||||
|
{
|
||||||
|
int n = 120;
|
||||||
|
char c = narrow<char>(n);
|
||||||
|
CHECK(c == 120);
|
||||||
|
|
||||||
|
n = 300;
|
||||||
|
CHECK_THROW(narrow<char>(n), narrowing_error);
|
||||||
|
|
||||||
|
const auto int32_max = std::numeric_limits<int32_t>::max();
|
||||||
|
const auto int32_min = std::numeric_limits<int32_t>::min();
|
||||||
|
|
||||||
|
CHECK(narrow<uint32_t>(int32_t(0)) == 0);
|
||||||
|
CHECK(narrow<uint32_t>(int32_t(1)) == 1);
|
||||||
|
CHECK(narrow<uint32_t>(int32_max) == int32_max);
|
||||||
|
|
||||||
|
CHECK_THROW(narrow<uint32_t>(int32_t(-1)), narrowing_error);
|
||||||
|
CHECK_THROW(narrow<uint32_t>(int32_min), narrowing_error);
|
||||||
|
|
||||||
|
n = -42;
|
||||||
|
CHECK_THROW(narrow<unsigned>(n), narrowing_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, const char *[])
|
||||||
|
{
|
||||||
|
return UnitTest::RunAllTests();
|
||||||
|
}
|
Loading…
Reference in New Issue