Added Guidelines Support Library (GSL)

This commit is contained in:
Daniel Wolf 2016-02-29 20:57:14 +01:00
parent 7f72504448
commit 4662113254
24 changed files with 7746 additions and 1 deletions

View File

@ -81,6 +81,9 @@ set_target_properties(gmock_main PROPERTIES FOLDER lib)
set_target_properties(gtest PROPERTIES FOLDER lib)
set_target_properties(gtest_main PROPERTIES FOLDER lib)
# ... GSL
include_directories(SYSTEM "lib/gsl/include")
# Define executable
include_directories("src" "src/audio_input")
configure_file(src/appInfo.cpp.in src/appInfo.cpp ESCAPE_QUOTES)

View File

@ -116,4 +116,19 @@ The [Google Test](https://github.com/google/googletest) framework is released un
> * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
> * 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.
>

21
lib/gsl/.clang-format Normal file
View File

@ -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

14
lib/gsl/.gitignore vendored Normal file
View File

@ -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

68
lib/gsl/.travis.yml Normal file
View File

@ -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

11
lib/gsl/CMakeLists.txt Normal file
View File

@ -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)

29
lib/gsl/CONTRIBUTING.md Normal file
View File

@ -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

21
lib/gsl/LICENSE Normal file
View File

@ -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.

67
lib/gsl/README.md Normal file
View File

@ -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!

168
lib/gsl/include/gsl.h Normal file
View File

@ -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

View File

@ -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

148
lib/gsl/include/gsl_util.h Normal file
View File

@ -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

2224
lib/gsl/include/span.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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)

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

1679
lib/gsl/tests/span_tests.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}