diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..b80d2c6 --- /dev/null +++ b/.clang-format @@ -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 diff --git a/.gitignore b/.gitignore index 5f5de3e..ea47eb3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,14 @@ -tests/unittest-cpp \ No newline at end of file +tests/unittest-cpp +CMakeFiles +tests/CMakeFiles +tests/Debug +*.opensdf +*.sdf +tests/*tests.dir +*.vcxproj +*.vcxproj.filters +*.sln +*.tlog +Testing/Temporary/*.* +CMakeCache.txt +*.suo diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..3c64230 --- /dev/null +++ b/.travis.yml @@ -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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 2125f7b..f8145d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ -cmake_minimum_required(VERSION 3.2.2) +cmake_minimum_required(VERSION 2.8.7) -project(GSL) +project(GSL CXX) include_directories( ${CMAKE_CURRENT_BINARY_DIR} @@ -8,4 +8,4 @@ include_directories( enable_testing() -add_subdirectory(tests) \ No newline at end of file +add_subdirectory(tests) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3ce68e8..990b8e1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ The Guidelines Support Library (GSL) contains functions and types that are sugge [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 the maintainers. Your pull request should include a link to the bug that you are fixing. If you've submitted +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 diff --git a/README.md b/README.md index 44d05e4..c687673 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ -# GSL: Guidelines Support Library +# 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](isocpp.org). -This repo contains Microsoft's implementation of GSL, tracking Microsoft's fork of the Guidelines. Microsoft's fork can be found here: -[C++ Core Guidelines](https://github.com/Microsoft/CppCoreGuidelines). +[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 `array_view<>`, `string_view<>`, `owner<>` and others. @@ -13,7 +12,7 @@ While some types have been broken out into their own headers (e.g. [include/arra 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. +other platforms. Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for more information about contributing. # Quick Start ## Supported Platforms @@ -25,16 +24,17 @@ The test suite that exercises GSL has been built and passes successfully on the * Windows using GCC 5.1 * GNU/Linux using Clang/LLVM 3.6 * GNU/Linux using GCC 5.1 -* Mac OS Yosemite using XCode with AppleClang 7.0.0.7000072 -* Mac OS Yosemite using GCC-5.2.0 +* 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. +> 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 3.3 or later to be installed and in your PATH. +* [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. @@ -47,13 +47,13 @@ These steps assume the source code of this repository has been cloned into a dir 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 diff --git a/include/array_view.h b/include/array_view.h index 006f18c..69559f6 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -16,48 +16,53 @@ #pragma once +#ifndef GSL_ARRAY_VIEW_H +#define GSL_ARRAY_VIEW_H + #include #include #include #include #include +#include #include #include #include #include +#include +#include #include "fail_fast.h" -#ifndef _MSC_VER -#define _CONSTEXPR constexpr -#else -#define _CONSTEXPR +#ifdef _MSC_VER + +// No MSVC does constexpr fully yet +#pragma push_macro("constexpr") +#define constexpr /* nothing */ + + +// VS 2013 workarounds +#if _MSC_VER <= 1800 + +// noexcept is not understood +#ifndef GSL_THROWS_FOR_TESTING +#define noexcept /* nothing */ #endif -#pragma push_macro("_NOEXCEPT") - -#ifndef _NOEXCEPT - -#ifdef SAFER_CPP_TESTING -#define _NOEXCEPT -#else -#define _NOEXCEPT noexcept -#endif - -#else // _NOEXCEPT - -#ifdef SAFER_CPP_TESTING -#undef _NOEXCEPT -#define _NOEXCEPT -#endif - -#endif // _NOEXCEPT - -#if defined(_MSC_VER) && _MSC_VER <= 1800 +// turn off some misguided warnings #pragma warning(push) #pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior + #endif // _MSC_VER <= 1800 -namespace Guide { +#endif // _MSC_VER + +// In order to test the library, we need it to throw exceptions that we can catch +#ifdef GSL_THROWS_FOR_TESTING +#define noexcept /* nothing */ +#endif // GSL_THROWS_FOR_TESTING + + +namespace gsl { /* ** begin definitions of index and bounds @@ -67,388 +72,166 @@ namespace details template struct SizeTypeTraits { - static const size_t max_value = std::is_signed::value ? static_cast::type>(-1) / 2 : static_cast(-1); + static const SizeType max_value = std::numeric_limits::max(); }; - template - class coordinate_facade - { - static_assert(std::is_integral::value - && sizeof(ValueType) <= sizeof(size_t), "ValueType must be unsigned integral type!"); - static_assert(Rank > 0, "Rank must be greater than 0!"); + template + class are_integral : public std::integral_constant {}; - template - friend class coordinate_facade; - public: - using reference = ValueType&; - using const_reference = const ValueType&; - using value_type = ValueType; - static const unsigned int rank = Rank; - _CONSTEXPR coordinate_facade() _NOEXCEPT - { - static_assert(std::is_base_of::value, "ConcreteType must be derived from coordinate_facade."); - } - _CONSTEXPR coordinate_facade(const value_type(&values)[rank]) _NOEXCEPT - { - static_assert(std::is_base_of::value, "ConcreteType must be derived from coordinate_facade."); - for (unsigned int i = 0; i < rank; ++i) - elems[i] = values[i]; - } - _CONSTEXPR coordinate_facade(value_type e0) _NOEXCEPT - { - static_assert(std::is_base_of::value, "ConcreteType must be derived from coordinate_facade."); - static_assert(rank == 1, "This constructor can only be used with rank == 1."); - elems[0] = e0; - } - // Preconditions: il.size() == rank - _CONSTEXPR coordinate_facade(std::initializer_list il) - { - static_assert(std::is_base_of::value, "ConcreteType must be derived from coordinate_facade."); - fail_fast_assert(il.size() == rank, "The size of the initializer list must match the rank of the array"); - for (unsigned int i = 0; i < rank; ++i) - { - elems[i] = begin(il)[i]; - } - } - - _CONSTEXPR coordinate_facade(const coordinate_facade & other) = default; - - template - _CONSTEXPR coordinate_facade(const coordinate_facade & other) - { - for (unsigned int i = 0; i < rank; ++i) - { - fail_fast_assert(static_cast(other.elems[i]) <= SizeTypeTraits::max_value); - elems[i] = static_cast(other.elems[i]); - } - } - protected: - coordinate_facade& operator=(const coordinate_facade& rhs) = default; - // Preconditions: component_idx < rank - _CONSTEXPR reference operator[](unsigned int component_idx) - { - fail_fast_assert(component_idx < rank, "Component index must be less than rank"); - return elems[component_idx]; - } - // Preconditions: component_idx < rank - _CONSTEXPR const_reference operator[](unsigned int component_idx) const - { - fail_fast_assert(component_idx < rank, "Component index must be less than rank"); - return elems[component_idx]; - } - _CONSTEXPR bool operator==(const ConcreteType& rhs) const _NOEXCEPT - { - for (unsigned int i = 0; i < rank; ++i) - { - if (elems[i] != rhs.elems[i]) - return false; - } - return true; - } - _CONSTEXPR bool operator!=(const ConcreteType& rhs) const _NOEXCEPT - { - return !(to_concrete() == rhs); - } - _CONSTEXPR ConcreteType operator+() const _NOEXCEPT - { - return to_concrete(); - } - _CONSTEXPR ConcreteType operator-() const - { - ConcreteType ret = to_concrete(); - for (unsigned int i = 0; i < rank; ++i) - ret.elems[i] = -ret.elems[i]; - return ret; - } - _CONSTEXPR ConcreteType operator+(const ConcreteType& rhs) const - { - ConcreteType ret = to_concrete(); - ret += rhs; - return ret; - } - _CONSTEXPR ConcreteType operator-(const ConcreteType& rhs) const - { - ConcreteType ret = to_concrete(); - ret -= rhs; - return ret; - } - _CONSTEXPR ConcreteType& operator+=(const ConcreteType& rhs) - { - for (unsigned int i = 0; i < rank; ++i) - elems[i] += rhs.elems[i]; - return to_concrete(); - } - _CONSTEXPR ConcreteType& operator-=(const ConcreteType& rhs) - { - for (unsigned int i = 0; i < rank; ++i) - elems[i] -= rhs.elems[i]; - return to_concrete(); - } - _CONSTEXPR ConcreteType& operator++() - { - static_assert(rank == 1, "This operator can only be used with rank == 1."); - ++elems[0]; - return to_concrete(); - } - _CONSTEXPR ConcreteType operator++(int) - { - static_assert(rank == 1, "This operator can only be used with rank == 1."); - ConcreteType ret = to_concrete(); - ++(*this); - return ret; - } - _CONSTEXPR ConcreteType& operator--() - { - static_assert(rank == 1, "This operator can only be used with rank == 1."); - --elems[0]; - return to_concrete(); - } - _CONSTEXPR ConcreteType operator--(int) - { - static_assert(rank == 1, "This operator can only be used with rank == 1."); - ConcreteType ret = to_concrete(); - --(*this); - return ret; - } - _CONSTEXPR ConcreteType operator*(value_type v) const - { - ConcreteType ret = to_concrete(); - ret *= v; - return ret; - } - _CONSTEXPR ConcreteType operator/(value_type v) const - { - ConcreteType ret = to_concrete(); - ret /= v; - return ret; - } - friend _CONSTEXPR ConcreteType operator*(value_type v, const ConcreteType& rhs) - { - return rhs * v; - } - _CONSTEXPR ConcreteType& operator*=(value_type v) - { - for (unsigned int i = 0; i < rank; ++i) - elems[i] *= v; - return to_concrete(); - } - _CONSTEXPR ConcreteType& operator/=(value_type v) - { - for (unsigned int i = 0; i < rank; ++i) - elems[i] /= v; - return to_concrete(); - } - value_type elems[rank] = {}; - private: - _CONSTEXPR const ConcreteType& to_concrete() const _NOEXCEPT - { - return static_cast(*this); - } - _CONSTEXPR ConcreteType& to_concrete() _NOEXCEPT - { - return static_cast(*this); - } - }; - template - class arrow_proxy - { - public: - explicit arrow_proxy(T t) - : val(t) - {} - const T operator*() const _NOEXCEPT - { - return val; - } - const T* operator->() const _NOEXCEPT - { - return &val; - } - private: - T val; - }; + template + class are_integral : public std::integral_constant::value && are_integral::value> {}; } -template -class index : private details::coordinate_facade, ValueType, Rank> +template +class index final { - using Base = details::coordinate_facade, ValueType, Rank>; - friend Base; - template + static_assert(std::is_integral::value, "ValueType must be an integral type!"); + static_assert(Rank > 0, "Rank must be greater than 0!"); + + template friend class index; + public: - using Base::rank; - using reference = typename Base::reference; - using const_reference = typename Base::const_reference; - using size_type = typename Base::value_type; - using value_type = typename Base::value_type; - _CONSTEXPR index() _NOEXCEPT : Base(){} - _CONSTEXPR index(const value_type (&values)[rank]) _NOEXCEPT : Base(values) {} - _CONSTEXPR index(std::initializer_list il) : Base(il) {} + static const size_t rank = Rank; + using value_type = std::remove_reference_t; + using reference = std::add_lvalue_reference_t; + using const_reference = std::add_lvalue_reference_t>; - _CONSTEXPR index(const index &) = default; + constexpr index() noexcept + {} - template - _CONSTEXPR index(const index &other) : Base(other) + constexpr index(const value_type(&values)[Rank]) noexcept { - } - _CONSTEXPR static index shift_left(const index& other) _NOEXCEPT - { - value_type (&arr)[rank] = (value_type(&)[rank])(*(other.elems + 1)); - return index(arr); + std::copy(values, values + Rank, elems); } - using Base::operator[]; - using Base::operator==; - using Base::operator!=; - using Base::operator+; - using Base::operator-; - using Base::operator+=; - using Base::operator-=; - using Base::operator++; - using Base::operator--; - using Base::operator*; - using Base::operator/; - using Base::operator*=; - using Base::operator/=; -}; + template::value, typename Dummy = std::enable_if_t> + constexpr index(Ts... ds) noexcept : elems{ static_cast(ds)... } + {} -template -class index<1, ValueType> -{ - template - friend class index; -public: - static const unsigned int rank = 1; - using reference = ValueType&; - using const_reference = const ValueType&; - using size_type = ValueType; - using value_type = ValueType; - - _CONSTEXPR index() _NOEXCEPT : value(0) + constexpr index(const index& other) noexcept = default; + + // copy from index over smaller domain + template ::max_value <= details::SizeTypeTraits::max_value), + typename Other = std::enable_if_t>> + constexpr index(const index& other) noexcept { - } - _CONSTEXPR index(value_type e0) _NOEXCEPT : value(e0) - { - } - _CONSTEXPR index(const value_type(&values)[1]) _NOEXCEPT : index(values[0]) - { - } - // Preconditions: il.size() == rank - _CONSTEXPR index(std::initializer_list il) - { - fail_fast_assert(il.size() == rank, "Size of the initializer list must match the rank of the array"); - value = begin(il)[0]; + std::copy(other.elems, other.elems + Rank, elems); } - _CONSTEXPR index(const index &) = default; - - template - _CONSTEXPR index(const index<1, OtherValueType> & other) + // copy from index over larger domain + template ::max_value > details::SizeTypeTraits::max_value), + typename Other = std::enable_if_t>> + constexpr index(const index& other, void* = 0) noexcept { - fail_fast_assert(other.value <= details::SizeTypeTraits::max_value); - value = static_cast(other.value); + bool ok = std::accumulate(other.elems, other.elems + Rank, true, + [&](bool b, OtherValueType val) { return b && (val <= static_cast(details::SizeTypeTraits::max_value)); } + ); + + fail_fast_assert(ok, "other value must fit in the new domain"); + std::transform(other.elems, other.elems + rank, elems, [&](OtherValueType val) { return static_cast(val); }); } - _CONSTEXPR static index shift_left(const index& other) _NOEXCEPT - { - return other.elems[1]; - } + constexpr index& operator=(const index& rhs) noexcept = default; + // Preconditions: component_idx < rank - _CONSTEXPR reference operator[](size_type component_idx) _NOEXCEPT + constexpr reference operator[](size_t component_idx) { - fail_fast_assert(component_idx == 0, "Component index must be less than rank"); - (void)(component_idx); - return value; + fail_fast_assert(component_idx < Rank, "Component index must be less than rank"); + return elems[component_idx]; } + // Preconditions: component_idx < rank - _CONSTEXPR const_reference operator[](size_type component_idx) const _NOEXCEPT + constexpr const_reference operator[](size_t component_idx) const noexcept { - fail_fast_assert(component_idx == 0, "Component index must be less than rank"); - (void)(component_idx); - return value; + fail_fast_assert(component_idx < Rank, "Component index must be less than rank"); + return elems[component_idx]; } - _CONSTEXPR bool operator==(const index& rhs) const _NOEXCEPT + + constexpr bool operator==(const index& rhs) const noexcept { - return value == rhs.value; + return std::equal(elems, elems + rank, rhs.elems); } - _CONSTEXPR bool operator!=(const index& rhs) const _NOEXCEPT + + constexpr bool operator!=(const index& rhs) const noexcept { - return !(*this == rhs); + return !(this == rhs); } - _CONSTEXPR index operator+() const _NOEXCEPT + + constexpr index operator+() const noexcept { return *this; } - _CONSTEXPR index operator-() const _NOEXCEPT - { - return index(-value); - } - _CONSTEXPR index operator+(const index& rhs) const _NOEXCEPT - { - return index(value + rhs.value); - } - _CONSTEXPR index operator-(const index& rhs) const _NOEXCEPT - { - return index(value - rhs.value); - } - _CONSTEXPR index& operator+=(const index& rhs) _NOEXCEPT - { - value += rhs.value; - return *this; - } - _CONSTEXPR index& operator-=(const index& rhs) _NOEXCEPT - { - value -= rhs.value; - return *this; - } - _CONSTEXPR index& operator++() _NOEXCEPT - { - ++value; - return *this; - } - _CONSTEXPR index operator++(int) _NOEXCEPT + + constexpr index operator-() const noexcept { index ret = *this; - ++(*this); + std::transform(ret, ret + rank, ret, std::negate{}); return ret; } - _CONSTEXPR index& operator--() _NOEXCEPT - { - --value; - return *this; - } - _CONSTEXPR index operator--(int) _NOEXCEPT + + constexpr index operator+(const index& rhs) const noexcept { index ret = *this; - --(*this); + ret += rhs; return ret; } - _CONSTEXPR index operator*(value_type v) const _NOEXCEPT + + constexpr index operator-(const index& rhs) const noexcept { - return index(value * v); + index ret = *this; + ret -= rhs; + return ret; } - _CONSTEXPR index operator/(value_type v) const _NOEXCEPT + + constexpr index& operator+=(const index& rhs) noexcept { - return index(value / v); - } - _CONSTEXPR index& operator*=(value_type v) _NOEXCEPT - { - value *= v; + std::transform(elems, elems + rank, rhs.elems, elems, std::plus{}); return *this; } - _CONSTEXPR index& operator/=(value_type v) _NOEXCEPT + + constexpr index& operator-=(const index& rhs) noexcept { - value /= v; + std::transform(elems, elems + rank, rhs.elems, elems, std::minus{}); return *this; } - friend _CONSTEXPR index operator*(value_type v, const index& rhs) _NOEXCEPT + + constexpr index operator*(value_type v) const noexcept { - return index(rhs * v); + index ret = *this; + ret *= v; + return ret; } + + constexpr index operator/(value_type v) const noexcept + { + index ret = *this; + ret /= v; + return ret; + } + + friend constexpr index operator*(value_type v, const index& rhs) noexcept + { + return rhs * v; + } + + constexpr index& operator*=(value_type v) noexcept + { + std::transform(elems, elems + rank, elems, [v](value_type x) { return std::multiplies{}(x, v); }); + return *this; + } + + constexpr index& operator/=(value_type v) noexcept + { + std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides{}(x, v); }); + return *this; + } + private: - value_type value; + value_type elems[Rank] = {}; }; #ifndef _MSC_VER @@ -537,8 +320,8 @@ namespace details template struct BoundsRanges { - static const unsigned int Depth = 0; - static const unsigned int DynamicNum = 0; + static const size_t Depth = 0; + static const size_t DynamicNum = 0; static const SizeType CurrentRange = 1; static const SizeType TotalSize = 1; @@ -546,28 +329,28 @@ namespace details // TODO : following signature is for work around VS bug template - BoundsRanges (const OtherType &, bool firstLevel) {} + BoundsRanges (const OtherType &, bool /* firstLevel */) {} BoundsRanges(const SizeType * const) { } BoundsRanges() = default; - template + template void serialize(T &) const { } - template + template SizeType linearize(const T &) const { return 0; } - template + template ptrdiff_t contains(const T &) const { return 0; } - size_t totalSize() const _NOEXCEPT { + size_t totalSize() const noexcept { return TotalSize; } - bool operator == (const BoundsRanges &) const _NOEXCEPT + bool operator == (const BoundsRanges &) const noexcept { return true; } @@ -576,8 +359,8 @@ namespace details template struct BoundsRanges : BoundsRanges{ using Base = BoundsRanges ; - static const unsigned int Depth = Base::Depth + 1; - static const unsigned int DynamicNum = Base::DynamicNum + 1; + static const size_t Depth = Base::Depth + 1; + static const size_t DynamicNum = Base::DynamicNum + 1; static const SizeType CurrentRange = dynamic_range; static const SizeType TotalSize = dynamic_range; const SizeType m_bound; @@ -591,24 +374,24 @@ namespace details BoundsRanges() : m_bound(0) {} template - BoundsRanges(const BoundsRanges &other, bool firstLevel = true) : + BoundsRanges(const BoundsRanges &other, bool /* firstLevel */ = true) : Base(static_cast&>(other), false), m_bound (static_cast(other.totalSize())) { } - template + template void serialize(T & arr) const { arr[Dim] = elementNum(); this->Base::template serialize(arr); } - template + template SizeType linearize(const T & arr) const { const size_t index = this->Base::totalSize() * arr[Dim]; fail_fast_assert(index < static_cast(m_bound)); return static_cast(index) + this->Base::template linearize(arr); } - template + template ptrdiff_t contains(const T & arr) const { const ptrdiff_t last = this->Base::template contains(arr); if (last == -1) @@ -617,22 +400,22 @@ namespace details return static_cast(cur) < static_cast(m_bound) ? cur + last : -1; } - size_t totalSize() const _NOEXCEPT { + size_t totalSize() const noexcept { return m_bound; } - SizeType elementNum() const _NOEXCEPT { + SizeType elementNum() const noexcept { return static_cast(totalSize() / this->Base::totalSize()); } - SizeType elementNum(unsigned int dim) const _NOEXCEPT{ + SizeType elementNum(size_t dim) const noexcept{ if (dim > 0) return this->Base::elementNum(dim - 1); else return elementNum(); } - bool operator == (const BoundsRanges & rhs) const _NOEXCEPT + bool operator == (const BoundsRanges & rhs) const noexcept { return m_bound == rhs.m_bound && static_cast(*this) == static_cast(rhs); } @@ -641,8 +424,8 @@ namespace details template struct BoundsRanges : BoundsRanges{ using Base = BoundsRanges ; - static const unsigned int Depth = Base::Depth + 1; - static const unsigned int DynamicNum = Base::DynamicNum; + static const size_t Depth = Base::Depth + 1; + static const size_t DynamicNum = Base::DynamicNum; static const SizeType CurrentRange = static_cast(CurRange); static const SizeType TotalSize = StaticSizeHelper::value; static_assert (CurRange <= SizeTypeTraits::max_value, "CurRange must be smaller than SizeType limits"); @@ -657,19 +440,19 @@ namespace details fail_fast_assert((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize()); } - template + template void serialize(T & arr) const { arr[Dim] = elementNum(); this->Base::template serialize(arr); } - template + template SizeType linearize(const T & arr) const { fail_fast_assert(arr[Dim] < CurrentRange, "Index is out of range"); return static_cast(this->Base::totalSize()) * arr[Dim] + this->Base::template linearize(arr); } - template + template ptrdiff_t contains(const T & arr) const { if (static_cast(arr[Dim]) >= CurrentRange) return -1; @@ -679,22 +462,22 @@ namespace details return static_cast(this->Base::totalSize() * arr[Dim]) + last; } - size_t totalSize() const _NOEXCEPT{ + size_t totalSize() const noexcept{ return CurrentRange * this->Base::totalSize(); } - SizeType elementNum() const _NOEXCEPT{ + SizeType elementNum() const noexcept{ return CurrentRange; } - SizeType elementNum(unsigned int dim) const _NOEXCEPT{ + SizeType elementNum(size_t dim) const noexcept{ if (dim > 0) return this->Base::elementNum(dim - 1); else return elementNum(); } - bool operator == (const BoundsRanges & rhs) const _NOEXCEPT + bool operator == (const BoundsRanges & rhs) const noexcept { return static_cast(*this) == static_cast(rhs); } @@ -732,17 +515,17 @@ namespace details { const TypeChain & obj; TypeListIndexer(const TypeChain & obj) :obj(obj){} - template + template const TypeChain & getObj(std::true_type) { return obj; } - template + template auto getObj(std::false_type) -> decltype(TypeListIndexer(static_cast(obj)).template get()) { return TypeListIndexer(static_cast(obj)).template get(); } - template + template auto get() -> decltype(getObj(std::integral_constant())) { return getObj(std::integral_constant()); @@ -754,6 +537,17 @@ namespace details { return TypeListIndexer(obj); } + + template 1), typename Ret = std::enable_if_t>> + constexpr Ret shift_left(const index& other) noexcept + { + Ret ret{}; + for (size_t i = 0; i < Rank - 1; ++i) + { + ret[i] = other[i + 1]; + } + return ret; + } } template @@ -762,7 +556,7 @@ class bounds_iterator; template class static_bounds { public: - static_bounds(const details::BoundsRanges &empty) { + static_bounds(const details::BoundsRanges &) { } }; @@ -774,225 +568,219 @@ class static_bounds && details::SizeTypeTraits::max_value <= SIZE_MAX, "SizeType must be an integral type and its numeric limits must be smaller than SIZE_MAX"); MyRanges m_ranges; - _CONSTEXPR static_bounds(const MyRanges & range) : m_ranges(range) { } + constexpr static_bounds(const MyRanges & range) : m_ranges(range) { } template friend class static_bounds; public: - static const unsigned int rank = MyRanges::Depth; - static const unsigned int dynamic_rank = MyRanges::DynamicNum; + static const size_t rank = MyRanges::Depth; + static const size_t dynamic_rank = MyRanges::DynamicNum; static const SizeType static_size = static_cast(MyRanges::TotalSize); using size_type = SizeType; using index_type = index; - using iterator = bounds_iterator; - using const_iterator = bounds_iterator; + using const_index_type = std::add_const_t; + using iterator = bounds_iterator; + using const_iterator = bounds_iterator; using difference_type = ptrdiff_t; using sliced_type = static_bounds; using mapping_type = contiguous_mapping_tag; public: - _CONSTEXPR static_bounds(const static_bounds &) = default; + constexpr static_bounds(const static_bounds &) = default; template , details::BoundsRanges >::value>> - _CONSTEXPR static_bounds(const static_bounds &other): + constexpr static_bounds(const static_bounds &other): m_ranges(other.m_ranges) { } - _CONSTEXPR static_bounds(std::initializer_list il) : m_ranges(il.begin()) + constexpr static_bounds(std::initializer_list il) : m_ranges(il.begin()) { fail_fast_assert(MyRanges::DynamicNum == il.size(), "Size of the initializer list must match the rank of the array"); fail_fast_assert(m_ranges.totalSize() <= details::SizeTypeTraits::max_value, "Size of the range is larger than the max element of the size type"); } - _CONSTEXPR static_bounds() = default; + constexpr static_bounds() = default; - _CONSTEXPR static_bounds & operator = (const static_bounds & otherBounds) + constexpr static_bounds & operator = (const static_bounds & otherBounds) { new(&m_ranges) MyRanges (otherBounds.m_ranges); return *this; } - _CONSTEXPR sliced_type slice() const _NOEXCEPT + constexpr sliced_type slice() const noexcept { return sliced_type{static_cast &>(m_ranges)}; } - _CONSTEXPR size_type stride() const _NOEXCEPT + constexpr size_type stride() const noexcept { return rank > 1 ? slice().size() : 1; } - _CONSTEXPR size_type size() const _NOEXCEPT + constexpr size_type size() const noexcept { return static_cast(m_ranges.totalSize()); } - _CONSTEXPR size_type total_size() const _NOEXCEPT + constexpr size_type total_size() const noexcept { return static_cast(m_ranges.totalSize()); } - _CONSTEXPR size_type linearize(const index_type & idx) const + constexpr size_type linearize(const index_type & idx) const { return m_ranges.linearize(idx); } - _CONSTEXPR bool contains(const index_type& idx) const _NOEXCEPT + constexpr bool contains(const index_type& idx) const noexcept { return m_ranges.contains(idx) != -1; } - _CONSTEXPR size_type operator[](unsigned int index) const _NOEXCEPT + constexpr size_type operator[](size_t index) const noexcept { return m_ranges.elementNum(index); } - template - _CONSTEXPR size_type extent() const _NOEXCEPT + template + constexpr size_type extent() const noexcept { static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)"); return details::createTypeListIndexer(m_ranges).template get().elementNum(); } - _CONSTEXPR index_type index_bounds() const _NOEXCEPT + constexpr index_type index_bounds() const noexcept { - index_type extents; + size_type extents[rank] = {}; m_ranges.serialize(extents); - return extents; + return{ extents }; } template - _CONSTEXPR bool operator == (const static_bounds & rhs) const _NOEXCEPT + constexpr bool operator == (const static_bounds & rhs) const noexcept { return this->size() == rhs.size(); } template - _CONSTEXPR bool operator != (const static_bounds & rhs) const _NOEXCEPT + constexpr bool operator != (const static_bounds & rhs) const noexcept { return !(*this == rhs); } - _CONSTEXPR const_iterator begin() const _NOEXCEPT + constexpr const_iterator begin() const noexcept { - return const_iterator(*this); + return const_iterator(*this, index_type{}); } - _CONSTEXPR const_iterator end() const _NOEXCEPT + constexpr const_iterator end() const noexcept { - index_type boundary; - m_ranges.serialize(boundary); return const_iterator(*this, this->index_bounds()); } }; -template -class strided_bounds : private details::coordinate_facade, SizeType, Rank> +template +class strided_bounds { - using Base = details::coordinate_facade, SizeType, Rank>; - friend Base; - template + template friend class strided_bounds; public: - using Base::rank; - using reference = typename Base::reference; - using const_reference = typename Base::const_reference; - using size_type = typename Base::value_type; - using difference_type = typename Base::value_type; - using value_type = typename Base::value_type; + static const size_t rank = Rank; + using reference = SizeType&; + using const_reference = const SizeType&; + using size_type = SizeType; + using difference_type = SizeType; + using value_type = SizeType; using index_type = index; - using iterator = bounds_iterator; - using const_iterator = bounds_iterator; + using const_index_type = std::add_const_t; + using iterator = bounds_iterator; + using const_iterator = bounds_iterator; static const int dynamic_rank = rank; static const size_t static_size = dynamic_range; using sliced_type = std::conditional_t, void>; using mapping_type = generalized_mapping_tag; - _CONSTEXPR strided_bounds(const strided_bounds &) = default; + constexpr strided_bounds(const strided_bounds &) noexcept = default; template - _CONSTEXPR strided_bounds(const strided_bounds &other) - : Base(other), m_strides(other.strides) + constexpr strided_bounds(const strided_bounds &other) noexcept + : m_extents(other.extents), m_strides(other.strides) + {} + constexpr strided_bounds(const index_type &extents, const index_type &strides) noexcept + : m_extents(extents), m_strides(strides) + {} + constexpr index_type strides() const noexcept { + return m_strides; } - - _CONSTEXPR strided_bounds(const index_type &extents, const index_type &strides) - : m_strides(strides) - { - for (unsigned int i = 0; i < rank; i++) - Base::elems[i] = extents[i]; - } - _CONSTEXPR strided_bounds(const value_type(&values)[rank], index_type strides) - : Base(values), m_strides(std::move(strides)) - { - } - _CONSTEXPR index_type strides() const _NOEXCEPT - { - return m_strides; - } - _CONSTEXPR size_type total_size() const _NOEXCEPT + constexpr size_type total_size() const noexcept { size_type ret = 0; - for (unsigned int i = 0; i < rank; ++i) - ret += (Base::elems[i] - 1) * m_strides[i]; + for (size_t i = 0; i < rank; ++i) + { + ret += (m_extents[i] - 1) * m_strides[i]; + } return ret + 1; } - _CONSTEXPR size_type size() const _NOEXCEPT + constexpr size_type size() const noexcept { size_type ret = 1; - for (unsigned int i = 0; i < rank; ++i) - ret *= Base::elems[i]; + for (size_t i = 0; i < rank; ++i) + { + ret *= m_extents[i]; + } return ret; } - _CONSTEXPR bool contains(const index_type& idx) const _NOEXCEPT + constexpr bool contains(const index_type& idx) const noexcept { - for (unsigned int i = 0; i < rank; ++i) + for (size_t i = 0; i < rank; ++i) { - if (idx[i] < 0 || idx[i] >= Base::elems[i]) + if (idx[i] < 0 || idx[i] >= m_extents[i]) return false; } return true; } - _CONSTEXPR size_type linearize(const index_type & idx) const + constexpr size_type linearize(const index_type & idx) const noexcept { size_type ret = 0; - for (unsigned int i = 0; i < rank; i++) + for (size_t i = 0; i < rank; i++) { - fail_fast_assert(idx[i] < Base::elems[i], "index is out of bounds of the array"); + fail_fast_assert(idx[i] < m_extents[i], "index is out of bounds of the array"); ret += idx[i] * m_strides[i]; } return ret; } - _CONSTEXPR size_type stride() const _NOEXCEPT + constexpr size_type stride() const noexcept { return m_strides[0]; } template 1), typename Ret = std::enable_if_t> - _CONSTEXPR sliced_type slice() const + constexpr sliced_type slice() const { - return{ (value_type(&)[rank - 1])Base::elems[1], sliced_type::index_type::shift_left(m_strides) }; + return{ details::shift_left(m_extents), details::shift_left(m_strides) }; } - template - _CONSTEXPR size_type extent() const _NOEXCEPT + template + constexpr size_type extent() const noexcept { static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)"); - return Base::elems[Dim]; + return m_extents[Dim]; } - _CONSTEXPR index_type index_bounds() const _NOEXCEPT + constexpr index_type index_bounds() const noexcept { - return index_type(Base::elems); + return m_extents; } - const_iterator begin() const _NOEXCEPT + constexpr const_iterator begin() const noexcept { - return const_iterator{ *this }; + return const_iterator{ *this, index_type{} }; } - const_iterator end() const _NOEXCEPT + constexpr const_iterator end() const noexcept { return const_iterator{ *this, index_bounds() }; } private: + index_type m_extents; index_type m_strides; }; @@ -1000,184 +788,197 @@ template struct is_bounds : std::integral_constant {}; template struct is_bounds> : std::integral_constant {}; -template +template struct is_bounds> : std::integral_constant {}; template -class bounds_iterator - : public std::iterator, - const IndexType> +class bounds_iterator: public std::iterator { private: - using Base = std::iterator , const IndexType>; + using Base = std::iterator ; + public: - static const unsigned int rank = IndexType::rank; + static const size_t rank = IndexType::rank; using typename Base::reference; using typename Base::pointer; using typename Base::difference_type; using typename Base::value_type; using index_type = value_type; - using index_size_type = typename IndexType::size_type; + using index_size_type = typename IndexType::value_type; template - explicit bounds_iterator(const Bounds & bnd, value_type curr = value_type{}) _NOEXCEPT - : boundary(bnd.index_bounds()) - , curr( std::move(curr) ) + explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept + : boundary(bnd.index_bounds()), curr(std::move(curr)) { static_assert(is_bounds::value, "Bounds type must be provided"); } - reference operator*() const _NOEXCEPT + + constexpr reference operator*() const noexcept { return curr; } - pointer operator->() const _NOEXCEPT + + constexpr pointer operator->() const noexcept { - return details::arrow_proxy{ curr }; + return &curr; } - bounds_iterator& operator++() _NOEXCEPT + + constexpr bounds_iterator& operator++() noexcept { - for (unsigned int i = rank; i-- > 0;) + for (size_t i = rank; i-- > 0;) { - if (++curr[i] < boundary[i]) + if (curr[i] < boundary[i] - 1) { + curr[i]++; return *this; } - else - { - curr[i] = 0; - } + curr[i] = 0; } // If we're here we've wrapped over - set to past-the-end. - for (unsigned int i = 0; i < rank; ++i) - { - curr[i] = boundary[i]; - } + curr = boundary; return *this; } - bounds_iterator operator++(int) _NOEXCEPT + + constexpr bounds_iterator operator++(int) noexcept { auto ret = *this; ++(*this); return ret; } - bounds_iterator& operator--() _NOEXCEPT + + constexpr bounds_iterator& operator--() noexcept { - for (int i = rank; i-- > 0;) + if (!less(curr, boundary)) { - if (curr[i]-- > 0) - { - return *this; - } - else + // if at the past-the-end, set to last element + for (size_t i = 0; i < rank; ++i) { curr[i] = boundary[i] - 1; } + return *this; + } + for (size_t i = rank; i-- > 0;) + { + if (curr[i] >= 1) + { + curr[i]--; + return *this; + } + curr[i] = boundary[i] - 1; } // If we're here the preconditions were violated // "pre: there exists s such that r == ++s" fail_fast_assert(false); return *this; } - bounds_iterator operator--(int) _NOEXCEPT + + constexpr bounds_iterator operator--(int) noexcept { auto ret = *this; --(*this); return ret; } - bounds_iterator operator+(difference_type n) const _NOEXCEPT + + constexpr bounds_iterator operator+(difference_type n) const noexcept { bounds_iterator ret{ *this }; return ret += n; } - bounds_iterator& operator+=(difference_type n) _NOEXCEPT + + constexpr bounds_iterator& operator+=(difference_type n) noexcept { auto linear_idx = linearize(curr) + n; - value_type stride; + std::remove_const_t stride = 0; stride[rank - 1] = 1; - for (unsigned int i = rank - 1; i-- > 0;) + for (size_t i = rank - 1; i-- > 0;) { stride[i] = stride[i + 1] * boundary[i + 1]; } - for (unsigned int i = 0; i < rank; ++i) + for (size_t i = 0; i < rank; ++i) { curr[i] = linear_idx / stride[i]; linear_idx = linear_idx % stride[i]; } + fail_fast_assert(!less(curr, index_type{}) && !less(boundary, curr), "index is out of bounds of the array"); return *this; } - bounds_iterator operator-(difference_type n) const _NOEXCEPT + + constexpr bounds_iterator operator-(difference_type n) const noexcept { bounds_iterator ret{ *this }; return ret -= n; } - bounds_iterator& operator-=(difference_type n) _NOEXCEPT + + constexpr bounds_iterator& operator-=(difference_type n) noexcept { return *this += -n; } - difference_type operator-(const bounds_iterator& rhs) const _NOEXCEPT + + constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept { return linearize(curr) - linearize(rhs.curr); } - reference operator[](difference_type n) const _NOEXCEPT + + constexpr reference operator[](difference_type n) const noexcept { return *(*this + n); } - bool operator==(const bounds_iterator& rhs) const _NOEXCEPT + + constexpr bool operator==(const bounds_iterator& rhs) const noexcept { return curr == rhs.curr; } - bool operator!=(const bounds_iterator& rhs) const _NOEXCEPT + + constexpr bool operator!=(const bounds_iterator& rhs) const noexcept { return !(*this == rhs); } - bool operator<(const bounds_iterator& rhs) const _NOEXCEPT + + constexpr bool operator<(const bounds_iterator& rhs) const noexcept { - for (unsigned int i = 0; i < rank; ++i) - { - if (curr[i] < rhs.curr[i]) - return true; - } - return false; + return less(curr, rhs.curr); } - bool operator<=(const bounds_iterator& rhs) const _NOEXCEPT + + constexpr bool operator<=(const bounds_iterator& rhs) const noexcept { return !(rhs < *this); } - bool operator>(const bounds_iterator& rhs) const _NOEXCEPT + + constexpr bool operator>(const bounds_iterator& rhs) const noexcept { return rhs < *this; } - bool operator>=(const bounds_iterator& rhs) const _NOEXCEPT + + constexpr bool operator>=(const bounds_iterator& rhs) const noexcept { return !(rhs > *this); } - void swap(bounds_iterator& rhs) _NOEXCEPT + + void swap(bounds_iterator& rhs) noexcept { std::swap(boundary, rhs.boundary); std::swap(curr, rhs.curr); } private: - index_size_type linearize(const value_type& idx) const _NOEXCEPT + constexpr bool less(index_type& one, index_type& other) const noexcept + { + for (size_t i = 0; i < rank; ++i) + { + if (one[i] < other[i]) + return true; + } + return false; + } + + constexpr index_size_type linearize(const value_type& idx) const noexcept { // TODO: Smarter impl. // Check if past-the-end - bool pte = true; - for (unsigned int i = 0; i < rank; ++i) - { - if (idx[i] != boundary[i]) - { - pte = false; - break; - } - } index_size_type multiplier = 1; index_size_type res = 0; - if (pte) + if (!less(idx, boundary)) { res = 1; - for (unsigned int i = rank; i-- > 0;) + for (size_t i = rank; i-- > 0;) { res += (idx[i] - 1) * multiplier; multiplier *= boundary[i]; @@ -1185,7 +986,7 @@ private: } else { - for (unsigned int i = rank; i-- > 0;) + for (size_t i = rank; i-- > 0;) { res += idx[i] * multiplier; multiplier *= boundary[i]; @@ -1193,123 +994,13 @@ private: } return res; } + value_type boundary; - value_type curr; -}; - -template -class bounds_iterator> - : public std::iterator, - ptrdiff_t, - const details::arrow_proxy>, - const index<1, SizeType>> -{ - using Base = std::iterator, ptrdiff_t, const details::arrow_proxy>, const index<1, SizeType>>; - -public: - using typename Base::reference; - using typename Base::pointer; - using typename Base::difference_type; - using typename Base::value_type; - using index_type = value_type; - using index_size_type = typename index_type::size_type; - - template - explicit bounds_iterator(const Bounds &, value_type curr = value_type{}) _NOEXCEPT - : curr( std::move(curr) ) - {} - reference operator*() const _NOEXCEPT - { - return curr; - } - pointer operator->() const _NOEXCEPT - { - return details::arrow_proxy{ curr }; - } - bounds_iterator& operator++() _NOEXCEPT - { - ++curr; - return *this; - } - bounds_iterator operator++(int) _NOEXCEPT - { - auto ret = *this; - ++(*this); - return ret; - } - bounds_iterator& operator--() _NOEXCEPT - { - curr--; - return *this; - } - bounds_iterator operator--(int) _NOEXCEPT - { - auto ret = *this; - --(*this); - return ret; - } - bounds_iterator operator+(difference_type n) const _NOEXCEPT - { - bounds_iterator ret{ *this }; - return ret += n; - } - bounds_iterator& operator+=(difference_type n) _NOEXCEPT - { - curr += n; - return *this; - } - bounds_iterator operator-(difference_type n) const _NOEXCEPT - { - bounds_iterator ret{ *this }; - return ret -= n; - } - bounds_iterator& operator-=(difference_type n) _NOEXCEPT - { - return *this += -n; - } - difference_type operator-(const bounds_iterator& rhs) const _NOEXCEPT - { - return curr[0] - rhs.curr[0]; - } - reference operator[](difference_type n) const _NOEXCEPT - { - return curr + n; - } - bool operator==(const bounds_iterator& rhs) const _NOEXCEPT - { - return curr == rhs.curr; - } - bool operator!=(const bounds_iterator& rhs) const _NOEXCEPT - { - return !(*this == rhs); - } - bool operator<(const bounds_iterator& rhs) const _NOEXCEPT - { - return curr[0] < rhs.curr[0]; - } - bool operator<=(const bounds_iterator& rhs) const _NOEXCEPT - { - return !(rhs < *this); - } - bool operator>(const bounds_iterator& rhs) const _NOEXCEPT - { - return rhs < *this; - } - bool operator>=(const bounds_iterator& rhs) const _NOEXCEPT - { - return !(rhs > *this); - } - void swap(bounds_iterator& rhs) _NOEXCEPT - { - std::swap(curr, rhs.curr); - } -private: - value_type curr; + std::remove_const_t curr; }; template -bounds_iterator operator+(typename bounds_iterator::difference_type n, const bounds_iterator& rhs) _NOEXCEPT +bounds_iterator operator+(typename bounds_iterator::difference_type n, const bounds_iterator& rhs) noexcept { return rhs + n; } @@ -1320,21 +1011,24 @@ bounds_iterator operator+(typename bounds_iterator::differ namespace details { template - _CONSTEXPR std::enable_if_t::value, typename Bounds::index_type> make_stride(const Bounds& bnd) _NOEXCEPT + constexpr std::enable_if_t::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept { return bnd.strides(); } - // Make a stride vector from bounds, assuming continugous memory. + // Make a stride vector from bounds, assuming contiguous memory. template - _CONSTEXPR std::enable_if_t::value, typename Bounds::index_type> make_stride(const Bounds& bnd) _NOEXCEPT + constexpr std::enable_if_t::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept { auto extents = bnd.index_bounds(); - typename Bounds::index_type stride; - stride[Bounds::rank - 1] = 1; - for (int i = Bounds::rank - 2; i >= 0; --i) - stride[i] = stride[i + 1] * extents[i + 1]; - return stride; + typename Bounds::size_type stride[Bounds::rank] = {}; + + stride[Bounds::rank - 1] = 1; + for (size_t i = 1; i < Bounds::rank; ++i) + { + stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i]; + } + return{ stride }; } template @@ -1359,15 +1053,16 @@ template class basic_array_view { public: - static const unsigned int rank = BoundsType::rank; + static const size_t rank = BoundsType::rank; using bounds_type = BoundsType; using size_type = typename bounds_type::size_type; using index_type = typename bounds_type::index_type; using value_type = ValueType; + using const_value_type = std::add_const_t; using pointer = ValueType*; using reference = ValueType&; using iterator = std::conditional_t::value, contiguous_array_view_iterator, general_array_view_iterator>; - using const_iterator = std::conditional_t::value, contiguous_array_view_iterator>, general_array_view_iterator>>; + using const_iterator = std::conditional_t::value, contiguous_array_view_iterator>, general_array_view_iterator>>; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using sliced_type = std::conditional_t>; @@ -1377,30 +1072,30 @@ private: bounds_type m_bounds; public: - _CONSTEXPR bounds_type bounds() const _NOEXCEPT + constexpr bounds_type bounds() const noexcept { return m_bounds; } - template - _CONSTEXPR size_type extent() const _NOEXCEPT + template + constexpr size_type extent() const noexcept { static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)"); return m_bounds.template extent(); } - _CONSTEXPR size_type size() const _NOEXCEPT + constexpr size_type size() const noexcept { return m_bounds.size(); } - _CONSTEXPR reference operator[](const index_type& idx) const + constexpr reference operator[](const index_type& idx) const { return m_pdata[m_bounds.linearize(idx)]; } - _CONSTEXPR pointer data() const _NOEXCEPT + constexpr pointer data() const noexcept { return m_pdata; } template 1), typename Ret = std::enable_if_t> - _CONSTEXPR Ret operator[](size_type idx) const + constexpr Ret operator[](size_type idx) const { fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array"); const size_type ridx = idx * m_bounds.stride(); @@ -1409,78 +1104,78 @@ public: return Ret {m_pdata + ridx, m_bounds.slice()}; } - _CONSTEXPR operator bool () const _NOEXCEPT + constexpr operator bool () const noexcept { return m_pdata != nullptr; } - _CONSTEXPR iterator begin() const + constexpr iterator begin() const { return iterator {this, true}; } - _CONSTEXPR iterator end() const + constexpr iterator end() const { - return iterator {this}; + return iterator {this, false}; } - _CONSTEXPR const_iterator cbegin() const + constexpr const_iterator cbegin() const { return const_iterator {reinterpret_cast *>(this), true}; } - _CONSTEXPR const_iterator cend() const + constexpr const_iterator cend() const { - return const_iterator {reinterpret_cast *>(this)}; + return const_iterator {reinterpret_cast *>(this), false}; } - _CONSTEXPR reverse_iterator rbegin() const + constexpr reverse_iterator rbegin() const { return reverse_iterator {end()}; } - _CONSTEXPR reverse_iterator rend() const + constexpr reverse_iterator rend() const { return reverse_iterator {begin()}; } - _CONSTEXPR const_reverse_iterator crbegin() const + constexpr const_reverse_iterator crbegin() const { return const_reverse_iterator {cend()}; } - _CONSTEXPR const_reverse_iterator crend() const + constexpr const_reverse_iterator crend() const { return const_reverse_iterator {cbegin()}; } template , std::remove_cv_t>::value>> - _CONSTEXPR bool operator== (const basic_array_view & other) const _NOEXCEPT + constexpr bool operator== (const basic_array_view & other) const noexcept { return m_bounds.size() == other.m_bounds.size() && (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin())); } template , std::remove_cv_t>::value>> - _CONSTEXPR bool operator!= (const basic_array_view & other) const _NOEXCEPT + constexpr bool operator!= (const basic_array_view & other) const noexcept { return !(*this == other); } template , std::remove_cv_t>::value>> - _CONSTEXPR bool operator< (const basic_array_view & other) const _NOEXCEPT + constexpr bool operator< (const basic_array_view & other) const noexcept { return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end()); } template , std::remove_cv_t>::value>> - _CONSTEXPR bool operator<= (const basic_array_view & other) const _NOEXCEPT + constexpr bool operator<= (const basic_array_view & other) const noexcept { return !(other < *this); } template , std::remove_cv_t>::value>> - _CONSTEXPR bool operator> (const basic_array_view & other) const _NOEXCEPT + constexpr bool operator> (const basic_array_view & other) const noexcept { return (other < *this); } template , std::remove_cv_t>::value>> - _CONSTEXPR bool operator>= (const basic_array_view & other) const _NOEXCEPT + constexpr bool operator>= (const basic_array_view & other) const noexcept { return !(*this < other); } @@ -1489,27 +1184,27 @@ public: template ::value && std::is_convertible::value>> - _CONSTEXPR basic_array_view(const basic_array_view & other ) _NOEXCEPT + constexpr basic_array_view(const basic_array_view & other ) noexcept : m_pdata(other.m_pdata), m_bounds(other.m_bounds) { } protected: - _CONSTEXPR basic_array_view(pointer data, bounds_type bound) _NOEXCEPT + constexpr basic_array_view(pointer data, bounds_type bound) noexcept : m_pdata(data) , m_bounds(std::move(bound)) { fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0); } template - _CONSTEXPR basic_array_view(T *data, std::enable_if_t>::value, bounds_type> bound) _NOEXCEPT + constexpr basic_array_view(T *data, std::enable_if_t>::value, bounds_type> bound) noexcept : m_pdata(reinterpret_cast(data)) , m_bounds(std::move(bound)) { fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0); } template - _CONSTEXPR basic_array_view as_array_view(const DestBounds &bounds) + constexpr basic_array_view as_array_view(const DestBounds &bounds) { details::verifyBoundsReshape(m_bounds, bounds); return {m_pdata, bounds}; @@ -1537,7 +1232,7 @@ struct dim template class array_view; -template +template class strided_array_view; namespace details @@ -1616,7 +1311,7 @@ namespace details template struct is_array_view_oracle> : std::true_type {}; - template + template struct is_array_view_oracle> : std::true_type {}; template @@ -1658,22 +1353,22 @@ public: public: // basic - _CONSTEXPR array_view(pointer ptr, bounds_type bounds) : Base(ptr, std::move(bounds)) + constexpr array_view(pointer ptr, bounds_type bounds) : Base(ptr, std::move(bounds)) { } - _CONSTEXPR array_view(std::nullptr_t) : Base(nullptr, bounds_type{}) + constexpr array_view(std::nullptr_t) : Base(nullptr, bounds_type{}) { } - _CONSTEXPR array_view(std::nullptr_t, size_type size) : Base(nullptr, bounds_type{}) + constexpr array_view(std::nullptr_t, size_type size) : Base(nullptr, bounds_type{}) { fail_fast_assert(size == 0); } // default template > - _CONSTEXPR array_view() : Base(nullptr, bounds_type()) + constexpr array_view() : Base(nullptr, bounds_type()) { } @@ -1681,7 +1376,7 @@ public: template , typename Dummy = std::enable_if_t::value && std::is_convertible::value>> - _CONSTEXPR array_view(T * const & data, size_type size) : Base(data, typename Helper::bounds_type{size}) + constexpr array_view(T * const & data, size_type size) : Base(data, typename Helper::bounds_type{size}) { } @@ -1689,7 +1384,7 @@ public: template , typename Dummy = std::enable_if_t::value && std::is_convertible::value>> - _CONSTEXPR array_view (T (&arr)[N]) : Base(arr, typename Helper::bounds_type()) + constexpr array_view (T (&arr)[N]) : Base(arr, typename Helper::bounds_type()) { } @@ -1697,19 +1392,19 @@ public: template , typename Dummy = std::enable_if_t::value && std::is_convertible::value >> - _CONSTEXPR array_view(T(&arr)[N], size_type size) : Base(arr, typename Helper::bounds_type{ size }) + constexpr array_view(T(&arr)[N], size_type size) : Base(arr, typename Helper::bounds_type{ size }) { fail_fast_assert(size <= N); } // from std array template , typename Base::bounds_type>::value>> - _CONSTEXPR array_view (std::array, N> & arr) : Base(arr.data(), static_bounds()) + constexpr array_view (std::array, N> & arr) : Base(arr.data(), static_bounds()) { } template , typename Base::bounds_type>::value && std::is_const::value>> - _CONSTEXPR array_view (const std::array, N> & arr) : Base(arr.data(), static_bounds()) + constexpr array_view (const std::array, N> & arr) : Base(arr.data(), static_bounds()) { } @@ -1718,7 +1413,7 @@ public: template ::value && details::LessThan::value>> // remove literal 0 case - _CONSTEXPR array_view (pointer begin, Ptr end) : Base(begin, details::newBoundsHelper(static_cast(end) - begin)) + constexpr array_view (pointer begin, Ptr end) : Base(begin, details::newBoundsHelper(static_cast(end) - begin)) { } @@ -1729,12 +1424,12 @@ public: && std::is_convertible, typename Base::bounds_type>::value && std::is_same().size(), *std::declval().data())>, DataType>::value> > - _CONSTEXPR array_view (Cont& cont) : Base(static_cast(cont.data()), details::newBoundsHelper(cont.size())) + constexpr array_view (Cont& cont) : Base(static_cast(cont.data()), details::newBoundsHelper(cont.size())) { } - _CONSTEXPR array_view(const array_view &) = default; + constexpr array_view(const array_view &) = default; // convertible template ::value_type, static_bounds::size_type, OtherDimensions...>>, typename Dummy = std::enable_if_t::value> > - _CONSTEXPR array_view(const array_view &av) : Base(static_cast::Base &>(av)) {} // static_cast is required + constexpr array_view(const array_view &av) : Base(static_cast::Base &>(av)) {} // static_cast is required // reshape template - _CONSTEXPR array_view as_array_view(Dimensions2... dims) + constexpr array_view as_array_view(Dimensions2... dims) { static_assert(sizeof...(Dimensions2) > 0, "the target array_view must have at least one dimension."); using BoundsType = typename array_view::bounds_type; @@ -1757,7 +1452,7 @@ public: // to bytes array template ::value_type>>::value> - _CONSTEXPR auto as_bytes() const _NOEXCEPT -> + constexpr auto as_bytes() const noexcept -> array_view, static_cast(details::StaticSizeHelper::value)> { static_assert(Enabled, "The value_type of array_view must be standarded layout"); @@ -1765,7 +1460,7 @@ public: } template ::value_type>>::value> - _CONSTEXPR auto as_writeable_bytes() const _NOEXCEPT -> + constexpr auto as_writeable_bytes() const noexcept -> array_view, static_cast(details::StaticSizeHelper::value)> { static_assert(Enabled, "The value_type of array_view must be standarded layout"); @@ -1775,7 +1470,7 @@ public: // from bytes array template::value, typename Dummy = std::enable_if_t> - _CONSTEXPR auto as_array_view() const _NOEXCEPT -> array_view(dynamic_range))> + constexpr auto as_array_view() const noexcept -> array_view(dynamic_range))> { static_assert(std::is_standard_layout::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % sizeof(U) == 0), "Target type must be standard layout and its size must match the byte array size"); @@ -1784,7 +1479,7 @@ public: } template::value, typename Dummy = std::enable_if_t> - _CONSTEXPR auto as_array_view() const _NOEXCEPT -> array_view(dynamic_range))> + constexpr auto as_array_view() const noexcept -> array_view(dynamic_range))> { static_assert(std::is_standard_layout::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % sizeof(U) == 0), "Target type must be standard layout and its size must match the byte array size"); @@ -1794,79 +1489,79 @@ public: // section on linear space template - _CONSTEXPR array_view first() const _NOEXCEPT + constexpr array_view first() const noexcept { static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound"); fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size()); // ensures we only check condition when needed return { this->data(), Count }; } - _CONSTEXPR array_view first(size_type count) const _NOEXCEPT + constexpr array_view first(size_type count) const noexcept { fail_fast_assert(count <= this->size()); return { this->data(), count }; } template - _CONSTEXPR array_view last() const _NOEXCEPT + constexpr array_view last() const noexcept { static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound"); fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size()); return { this->data() + this->size() - Count, Count }; } - _CONSTEXPR array_view last(size_type count) const _NOEXCEPT + constexpr array_view last(size_type count) const noexcept { fail_fast_assert(count <= this->size()); return { this->data() + this->size() - count, count }; } template - _CONSTEXPR array_view sub() const _NOEXCEPT + constexpr array_view sub() const noexcept { static_assert(bounds_type::static_size == dynamic_range || ((Offset == 0 || Offset <= bounds_type::static_size) && Offset + Count <= bounds_type::static_size), "Index is out of bound"); fail_fast_assert(bounds_type::static_size != dynamic_range || ((Offset == 0 || Offset <= this->size()) && Offset + Count <= this->size())); return { this->data() + Offset, Count }; } - _CONSTEXPR array_view sub(size_type offset, size_type count = dynamic_range) const _NOEXCEPT + constexpr array_view sub(size_type offset, size_type count = dynamic_range) const noexcept { fail_fast_assert((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size())); return { this->data() + offset, count == dynamic_range ? this->length() - offset : count }; } // size - _CONSTEXPR size_type length() const _NOEXCEPT + constexpr size_type length() const noexcept { return this->size(); } - _CONSTEXPR size_type used_length() const _NOEXCEPT + constexpr size_type used_length() const noexcept { return length(); } - _CONSTEXPR size_type bytes() const _NOEXCEPT + constexpr size_type bytes() const noexcept { return sizeof(value_type) * this->size(); } - _CONSTEXPR size_type used_bytes() const _NOEXCEPT + constexpr size_type used_bytes() const noexcept { return bytes(); } // section - _CONSTEXPR strided_array_view section(index_type origin, index_type extents) const + constexpr strided_array_view section(index_type origin, index_type extents) const { size_type size = this->bounds().total_size() - this->bounds().linearize(origin); return{ &this->operator[](origin), size, strided_bounds {extents, details::make_stride(Base::bounds())} }; } - _CONSTEXPR reference operator[](const index_type& idx) const + constexpr reference operator[](const index_type& idx) const { return Base::operator[](idx); } template 1), typename Dummy = std::enable_if_t> - _CONSTEXPR array_view operator[](size_type idx) const + constexpr array_view operator[](size_type idx) const { auto ret = Base::operator[](idx); return{ ret.data(), ret.bounds() }; @@ -1881,61 +1576,61 @@ public: }; template -_CONSTEXPR auto as_array_view(T * const & ptr, dim... args) -> array_view, Dimensions...> +constexpr auto as_array_view(T * const & ptr, dim... args) -> array_view, Dimensions...> { return {reinterpret_cast*>(ptr), details::static_as_array_view_helper>(args..., details::Sep{})}; } template -_CONSTEXPR auto as_array_view (T * arr, size_t len) -> typename details::ArrayViewArrayTraits::type +constexpr auto as_array_view (T * arr, size_t len) -> typename details::ArrayViewArrayTraits::type { return {arr, len}; } template -_CONSTEXPR auto as_array_view (T (&arr)[N]) -> typename details::ArrayViewArrayTraits::type +constexpr auto as_array_view (T (&arr)[N]) -> typename details::ArrayViewArrayTraits::type { return {arr}; } template -_CONSTEXPR array_view as_array_view(const std::array &arr) +constexpr array_view as_array_view(const std::array &arr) { return {arr}; } template -_CONSTEXPR array_view as_array_view(const std::array &&) = delete; +constexpr array_view as_array_view(const std::array &&) = delete; template -_CONSTEXPR array_view as_array_view(std::array &arr) +constexpr array_view as_array_view(std::array &arr) { return {arr}; } template -_CONSTEXPR array_view as_array_view(T *begin, T *end) +constexpr array_view as_array_view(T *begin, T *end) { return {begin, end}; } template -_CONSTEXPR auto as_array_view(Cont &arr) -> std::enable_if_t>::value, +constexpr auto as_array_view(Cont &arr) -> std::enable_if_t>::value, array_view, dynamic_range>> { return {arr.data(), arr.size()}; } template -_CONSTEXPR auto as_array_view(Cont &&arr) -> std::enable_if_t>::value, +constexpr auto as_array_view(Cont &&arr) -> std::enable_if_t>::value, array_view, dynamic_range>> = delete; -template +template class strided_array_view : public basic_array_view::value_type, strided_bounds::size_type>> { using Base = basic_array_view::value_type, strided_bounds::size_type>>; - template + template friend class strided_array_view; public: using Base::rank; @@ -1974,7 +1669,7 @@ public: typename OtherBaseType = basic_array_view::value_type, strided_bounds::size_type>>, typename Dummy = std::enable_if_t::value> > - _CONSTEXPR strided_array_view(const strided_array_view &av): Base(static_cast::Base &>(av)) // static_cast is required + constexpr strided_array_view(const strided_array_view &av): Base(static_cast::Base &>(av)) // static_cast is required { } @@ -1995,13 +1690,13 @@ public: return { &this->operator[](origin), size, bounds_type {extents, details::make_stride(Base::bounds())}}; } - _CONSTEXPR reference operator[](const index_type& idx) const + constexpr reference operator[](const index_type& idx) const { return Base::operator[](idx); } template 1), typename Dummy = std::enable_if_t> - _CONSTEXPR strided_array_view operator[](size_type idx) const + constexpr strided_array_view operator[](size_type idx) const { auto ret = Base::operator[](idx); return{ ret.data(), ret.bounds().total_size(), ret.bounds() }; @@ -2019,7 +1714,7 @@ private: } template > - static index_type resize_stride(const index_type& strides, size_t d, void *p = 0) + static index_type resize_stride(const index_type& strides, size_t , void * = 0) { fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized"); @@ -2032,10 +1727,8 @@ private: fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized"); fail_fast_assert(strides[rank - 2] >= d && (strides[rank - 2] % d == 0), "The strides must have contiguous chunks of memory that can contain a multiple of new type elements"); - for (int i = rank - 2; i >= 0; --i) - { - fail_fast_assert((strides[i] >= strides[i + 1]) && (strides[i] % strides[i + 1] == 0), "Only strided arrays with regular strides can be resized"); - } + for (size_t i = rank - 1; i > 0; --i) + fail_fast_assert((strides[i-1] >= strides[i]) && (strides[i-1] % strides[i] == 0), "Only strided arrays with regular strides can be resized"); index_type ret = strides / d; ret[rank - 1] = 1; @@ -2061,96 +1754,96 @@ private: { fail_fast_assert(m_pdata >= m_validator->m_pdata && m_pdata < m_validator->m_pdata + m_validator->size(), "iterator is out of range of the array"); } - contiguous_array_view_iterator (const ArrayView *container, bool isbegin = false) : - m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) { } + contiguous_array_view_iterator (const ArrayView *container, bool isbegin) : + m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) {} public: - reference operator*() const _NOEXCEPT + reference operator*() const noexcept { validateThis(); return *m_pdata; } - pointer operator->() const _NOEXCEPT + pointer operator->() const noexcept { validateThis(); return m_pdata; } - contiguous_array_view_iterator& operator++() _NOEXCEPT + contiguous_array_view_iterator& operator++() noexcept { ++m_pdata; return *this; } - contiguous_array_view_iterator operator++(int)_NOEXCEPT + contiguous_array_view_iterator operator++(int)noexcept { auto ret = *this; ++(*this); return ret; } - contiguous_array_view_iterator& operator--() _NOEXCEPT + contiguous_array_view_iterator& operator--() noexcept { --m_pdata; return *this; } - contiguous_array_view_iterator operator--(int)_NOEXCEPT + contiguous_array_view_iterator operator--(int)noexcept { auto ret = *this; --(*this); return ret; } - contiguous_array_view_iterator operator+(difference_type n) const _NOEXCEPT + contiguous_array_view_iterator operator+(difference_type n) const noexcept { contiguous_array_view_iterator ret{ *this }; return ret += n; } - contiguous_array_view_iterator& operator+=(difference_type n) _NOEXCEPT + contiguous_array_view_iterator& operator+=(difference_type n) noexcept { m_pdata += n; return *this; } - contiguous_array_view_iterator operator-(difference_type n) const _NOEXCEPT + contiguous_array_view_iterator operator-(difference_type n) const noexcept { contiguous_array_view_iterator ret{ *this }; return ret -= n; } - contiguous_array_view_iterator& operator-=(difference_type n) _NOEXCEPT + contiguous_array_view_iterator& operator-=(difference_type n) noexcept { return *this += -n; } - difference_type operator-(const contiguous_array_view_iterator& rhs) const _NOEXCEPT + difference_type operator-(const contiguous_array_view_iterator& rhs) const noexcept { fail_fast_assert(m_validator == rhs.m_validator); return m_pdata - rhs.m_pdata; } - reference operator[](difference_type n) const _NOEXCEPT + reference operator[](difference_type n) const noexcept { return *(*this + n); } - bool operator==(const contiguous_array_view_iterator& rhs) const _NOEXCEPT + bool operator==(const contiguous_array_view_iterator& rhs) const noexcept { fail_fast_assert(m_validator == rhs.m_validator); return m_pdata == rhs.m_pdata; } - bool operator!=(const contiguous_array_view_iterator& rhs) const _NOEXCEPT + bool operator!=(const contiguous_array_view_iterator& rhs) const noexcept { return !(*this == rhs); } - bool operator<(const contiguous_array_view_iterator& rhs) const _NOEXCEPT + bool operator<(const contiguous_array_view_iterator& rhs) const noexcept { fail_fast_assert(m_validator == rhs.m_validator); return m_pdata < rhs.m_pdata; } - bool operator<=(const contiguous_array_view_iterator& rhs) const _NOEXCEPT + bool operator<=(const contiguous_array_view_iterator& rhs) const noexcept { return !(rhs < *this); } - bool operator>(const contiguous_array_view_iterator& rhs) const _NOEXCEPT + bool operator>(const contiguous_array_view_iterator& rhs) const noexcept { return rhs < *this; } - bool operator>=(const contiguous_array_view_iterator& rhs) const _NOEXCEPT + bool operator>=(const contiguous_array_view_iterator& rhs) const noexcept { return !(rhs > *this); } - void swap(contiguous_array_view_iterator& rhs) _NOEXCEPT + void swap(contiguous_array_view_iterator& rhs) noexcept { std::swap(m_pdata, rhs.m_pdata); std::swap(m_validator, rhs.m_validator); @@ -2158,7 +1851,7 @@ public: }; template -contiguous_array_view_iterator operator+(typename contiguous_array_view_iterator::difference_type n, const contiguous_array_view_iterator& rhs) _NOEXCEPT +contiguous_array_view_iterator operator+(typename contiguous_array_view_iterator::difference_type n, const contiguous_array_view_iterator& rhs) noexcept { return rhs + n; } @@ -2177,96 +1870,96 @@ private: friend class basic_array_view; const ArrayView * m_container; typename ArrayView::bounds_type::iterator m_itr; - general_array_view_iterator(const ArrayView *container, bool isbegin = false) : + general_array_view_iterator(const ArrayView *container, bool isbegin) : m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end()) { } public: - reference operator*() const _NOEXCEPT + reference operator*() noexcept { return (*m_container)[*m_itr]; } - pointer operator->() const _NOEXCEPT + pointer operator->() noexcept { return &(*m_container)[*m_itr]; } - general_array_view_iterator& operator++() _NOEXCEPT + general_array_view_iterator& operator++() noexcept { ++m_itr; return *this; } - general_array_view_iterator operator++(int)_NOEXCEPT + general_array_view_iterator operator++(int)noexcept { auto ret = *this; ++(*this); return ret; } - general_array_view_iterator& operator--() _NOEXCEPT + general_array_view_iterator& operator--() noexcept { --m_itr; return *this; } - general_array_view_iterator operator--(int)_NOEXCEPT + general_array_view_iterator operator--(int)noexcept { auto ret = *this; --(*this); return ret; } - general_array_view_iterator operator+(difference_type n) const _NOEXCEPT + general_array_view_iterator operator+(difference_type n) const noexcept { general_array_view_iterator ret{ *this }; return ret += n; } - general_array_view_iterator& operator+=(difference_type n) _NOEXCEPT + general_array_view_iterator& operator+=(difference_type n) noexcept { m_itr += n; return *this; } - general_array_view_iterator operator-(difference_type n) const _NOEXCEPT + general_array_view_iterator operator-(difference_type n) const noexcept { general_array_view_iterator ret{ *this }; return ret -= n; } - general_array_view_iterator& operator-=(difference_type n) _NOEXCEPT + general_array_view_iterator& operator-=(difference_type n) noexcept { return *this += -n; } - difference_type operator-(const general_array_view_iterator& rhs) const _NOEXCEPT + difference_type operator-(const general_array_view_iterator& rhs) const noexcept { fail_fast_assert(m_container == rhs.m_container); return m_itr - rhs.m_itr; } - value_type operator[](difference_type n) const _NOEXCEPT + value_type operator[](difference_type n) const noexcept { return (*m_container)[m_itr[n]];; } - bool operator==(const general_array_view_iterator& rhs) const _NOEXCEPT + bool operator==(const general_array_view_iterator& rhs) const noexcept { fail_fast_assert(m_container == rhs.m_container); return m_itr == rhs.m_itr; } - bool operator !=(const general_array_view_iterator& rhs) const _NOEXCEPT + bool operator !=(const general_array_view_iterator& rhs) const noexcept { return !(*this == rhs); } - bool operator<(const general_array_view_iterator& rhs) const _NOEXCEPT + bool operator<(const general_array_view_iterator& rhs) const noexcept { fail_fast_assert(m_container == rhs.m_container); return m_itr < rhs.m_itr; } - bool operator<=(const general_array_view_iterator& rhs) const _NOEXCEPT + bool operator<=(const general_array_view_iterator& rhs) const noexcept { return !(rhs < *this); } - bool operator>(const general_array_view_iterator& rhs) const _NOEXCEPT + bool operator>(const general_array_view_iterator& rhs) const noexcept { return rhs < *this; } - bool operator>=(const general_array_view_iterator& rhs) const _NOEXCEPT + bool operator>=(const general_array_view_iterator& rhs) const noexcept { return !(rhs > *this); } - void swap(general_array_view_iterator& rhs) _NOEXCEPT + void swap(general_array_view_iterator& rhs) noexcept { std::swap(m_itr, rhs.m_itr); std::swap(m_container, rhs.m_container); @@ -2274,15 +1967,32 @@ public: }; template -general_array_view_iterator operator+(typename general_array_view_iterator::difference_type n, const general_array_view_iterator& rhs) _NOEXCEPT +general_array_view_iterator operator+(typename general_array_view_iterator::difference_type n, const general_array_view_iterator& rhs) noexcept { return rhs + n; } -} // namespace Guide +} // namespace gsl -#if defined(_MSC_VER) && _MSC_VER <= 1800 +#ifdef _MSC_VER + +#undef constexpr +#pragma pop_macro("constexpr") + +#if _MSC_VER <= 1800 #pragma warning(pop) + +#ifndef GSL_THROWS_FOR_TESTING +#pragma undef noexcept +#endif // GSL_THROWS_FOR_TESTING + #endif // _MSC_VER <= 1800 -#pragma pop_macro("_NOEXCEPT") +#endif // _MSC_VER + +#if defined(GSL_THROWS_FOR_TESTING) +#undef noexcept +#endif // GSL_THROWS_FOR_TESTING + + +#endif // GSL_ARRAY_VIEW_H diff --git a/include/fail_fast.h b/include/fail_fast.h index 382b9d6..b9982eb 100644 --- a/include/fail_fast.h +++ b/include/fail_fast.h @@ -16,16 +16,23 @@ #pragma once +#ifndef GSL_FAIL_FAST_H +#define GSL_FAIL_FAST_H + #include -namespace Guide +#if defined(GSL_THROWS_FOR_TESTING) +#include +#endif + +namespace gsl { // // Having "fail fast" result in an exception makes unit testing // the GSL classes that rely upon it much simpler. // -#if defined(SAFER_CPP_TESTING) +#if defined(GSL_THROWS_FOR_TESTING) struct fail_fast : public std::runtime_error { @@ -41,6 +48,8 @@ inline void fail_fast_assert(bool cond, const char* const message) { if (!cond) inline void fail_fast_assert(bool cond) { if (!cond) std::terminate(); } inline void fail_fast_assert(bool cond, const char* const) { if (!cond) std::terminate(); } -#endif // SAFER_CPP_TESTING +#endif // GSL_THROWS_FOR_TESTING } + +#endif // GSL_FAIL_FAST_H diff --git a/include/gsl.h b/include/gsl.h index cf6eca5..ec75723 100644 --- a/include/gsl.h +++ b/include/gsl.h @@ -16,11 +16,42 @@ #pragma once +#ifndef GSL_GSL_H +#define GSL_GSL_H + #include "array_view.h" // array_view, strided_array_view... #include "string_view.h" // zstring, string_view, zstring_builder... #include -namespace Guide +#ifdef _MSC_VER + +// No MSVC does constexpr fully yet +#pragma push_macro("constexpr") +#define constexpr /* nothing */ + +// MSVC 2013 workarounds +#if _MSC_VER <= 1800 + +// noexcept is not understood +#ifndef GSL_THROWS_FOR_TESTING +#define noexcept /* nothing */ +#endif + +// 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 + +// In order to test the library, we need it to throw exceptions that we can catch +#ifdef GSL_THROWS_FOR_TESTING +#define noexcept /* nothing */ +#endif // GSL_THROWS_FOR_TESTING + + +namespace gsl { // @@ -35,37 +66,41 @@ using owner = T; // // GSL.assert: assertions // -#define Expects(x) Guide::fail_fast_assert((x)) -#define Ensures(x) Guide::fail_fast_assert((x)) +#define Expects(x) gsl::fail_fast_assert((x)) +#define Ensures(x) gsl::fail_fast_assert((x)) // // GSL.util: utilities // -// Final_act allows you to ensure something gets run at the end of a scope +// final_act allows you to ensure something gets run at the end of a scope template -class Final_act +class final_act { public: - explicit Final_act(F f) : f_(f) {} - - Final_act(const Final_act&& other) : f_(other.f_) {} - Final_act(const Final_act&) = delete; - Final_act& operator=(const Final_act&) = delete; - - ~Final_act() { f_(); } + 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 +// finally() - convenience function to generate a final_act template -Final_act finally(F f) { return Final_act(f); } +final_act finally(const F &f) noexcept { return final_act(f); } + +template +final_act finally(F &&f) noexcept { return final_act(std::forward(f)); } // narrow_cast(): a searchable way to do narrowing casts of values template -T narrow_cast(U u) { return static_cast(u); } +T narrow_cast(U u) noexcept { return static_cast(u); } struct narrowing_error : public std::exception {}; // narrow() : a checked version of narrow_cast() that throws if the cast changed the value @@ -102,23 +137,30 @@ typename Cont::value_type& at(Cont& cont, size_t index) { fail_fast_assert(index template class not_null { + static_assert(std::is_assignable::value, "T cannot be assigned nullptr."); public: not_null(T t) : ptr_(t) { ensure_invariant(); } - - // deleting these two prevents compilation when initialized with a nullptr or literal 0 - not_null(std::nullptr_t) = delete; - not_null(int) = delete; + 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 ::value>> - not_null(const not_null &other) : ptr_(other.get()) + not_null(const not_null &other) { + *this = other; } - not_null& operator=(const T& t) { ptr_ = t; ensure_invariant(); return *this; } + template ::value>> + not_null& operator=(const not_null &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& operator=(std::nullptr_t) = delete; not_null& operator=(int) = delete; @@ -153,135 +195,39 @@ private: not_null& operator-=(size_t) = delete; }; +} // namespace gsl -// -// maybe_null -// -// Describes an optional pointer - provides symmetry with not_null -// -template -class maybe_null_dbg +namespace std { -public: - maybe_null_dbg() : ptr_(nullptr), tested_(false) {} - - maybe_null_dbg(const T& p) : ptr_(p), tested_(false) {} - maybe_null_dbg(const maybe_null_dbg& rhs) : ptr_(rhs.ptr_), tested_(false) {} - - template ::value>> - maybe_null_dbg(const not_null &other) : ptr_(other.get()), tested_(false) + template + struct hash> { - } - - template ::value>> - maybe_null_dbg(const maybe_null_dbg &other) : ptr_(other.get()), tested_(false) - { - } - - maybe_null_dbg& operator=(const T& p) - { - if (ptr_ != p) + size_t operator()(const gsl::not_null & value) const { - ptr_ = p; - tested_ = false; + return hash{}(value); } - return *this; - } + }; - maybe_null_dbg& operator=(const maybe_null_dbg& rhs) - { - if (this != &rhs) - { - ptr_ = rhs.ptr_; - tested_ = false; - } - return *this; - } +} // namespace std - bool present() const { tested_ = true; return ptr_ != nullptr; } - - bool operator==(const T& rhs) const { tested_ = true; return ptr_ == rhs; } - bool operator!=(const T& rhs) const { return !(*this == rhs); } - - T get() const { - fail_fast_assert(tested_); #ifdef _MSC_VER - __assume(ptr_ != nullptr); -#endif - return ptr_; - } - operator T() const { return get(); } - T operator->() const { return get(); } +#undef constexpr +#pragma pop_macro("constexpr") -private: - const size_t ptee_size_ = sizeof(*ptr_); // T must be a pointer type +#if _MSC_VER <= 1800 +#pragma warning(pop) - // unwanted operators...pointers only point to single objects! - // TODO ensure all arithmetic ops on this type are unavailable - maybe_null_dbg& operator++() = delete; - maybe_null_dbg& operator--() = delete; - maybe_null_dbg operator++(int) = delete; - maybe_null_dbg operator--(int) = delete; - maybe_null_dbg& operator+(size_t) = delete; - maybe_null_dbg& operator+=(size_t) = delete; - maybe_null_dbg& operator-(size_t) = delete; - maybe_null_dbg& operator-=(size_t) = delete; +#ifndef GSL_THROWS_FOR_TESTING +#pragma undef noexcept +#endif // GSL_THROWS_FOR_TESTING - T ptr_; - mutable bool tested_; -}; +#endif // _MSC_VER <= 1800 -template -class maybe_null_ret -{ -public: - maybe_null_ret() : ptr_(nullptr) {} - maybe_null_ret(std::nullptr_t) : ptr_(nullptr) {} - maybe_null_ret(const T& p) : ptr_(p) {} - maybe_null_ret(const maybe_null_ret& rhs) = default; +#endif // _MSC_VER - template ::value>> - maybe_null_ret(const not_null &other) : ptr_(other.get()) - { - } +#if defined(GSL_THROWS_FOR_TESTING) +#undef noexcept +#endif // GSL_THROWS_FOR_TESTING - template ::value>> - maybe_null_ret(const maybe_null_ret &other) : ptr_(other.get()) - { - } - - template ::value>> - maybe_null_ret(const maybe_null_dbg &other) : ptr_(other.get()) - { - } - - maybe_null_ret& operator=(const T& p) { if (ptr_ != p) { ptr_ = p; } return *this; } - maybe_null_ret& operator=(const maybe_null_ret& rhs) = default; - - bool present() const { return ptr_ != nullptr; } - - T get() const { return ptr_; } - - operator T() const { return get(); } - T operator->() const { return get(); } - -private: - // unwanted operators...pointers only point to single objects! - // TODO ensure all arithmetic ops on this type are unavailable - maybe_null_ret& operator++() = delete; - maybe_null_ret& operator--() = delete; - maybe_null_ret operator++(int) = delete; - maybe_null_ret operator--(int) = delete; - maybe_null_ret& operator+(size_t) = delete; - maybe_null_ret& operator+=(size_t) = delete; - maybe_null_ret& operator-(size_t) = delete; - maybe_null_ret& operator-=(size_t) = delete; - - const size_t ptee_size_ = sizeof(*ptr_); // T must be a pointer type - T ptr_; -}; - -template using maybe_null = maybe_null_ret; - -} // namespace Guide +#endif // GSL_GSL_H diff --git a/include/string_view.h b/include/string_view.h index 7becc8e..7080ce5 100644 --- a/include/string_view.h +++ b/include/string_view.h @@ -16,10 +16,13 @@ #pragma once +#ifndef GSL_STRING_VIEW_H +#define GSL_STRING_VIEW_H + #include "array_view.h" #include -namespace Guide +namespace gsl { // // czstring and wzstring @@ -79,9 +82,9 @@ template array_view ensure_sentinel(const T* seq, SizeType max = std::numeric_limits::max()) { auto cur = seq; - while ((cur - seq) < max && *cur != Sentinel) ++cur; + while (SizeType(cur - seq) < max && *cur != Sentinel) ++cur; fail_fast_assert(*cur == Sentinel); - return{ seq, cur - seq }; + return{ seq, SizeType(cur - seq) }; } @@ -93,7 +96,7 @@ array_view ensure_sentinel(const T* seq, SizeType max = std::n template inline basic_string_view ensure_z(T* const & sz, size_t max = std::numeric_limits::max()) { - return ensure_sentinel<0>(sz, max); + return ensure_sentinel(sz, max); } // TODO (neilmac) there is probably a better template-magic way to get the const and non-const overloads to share an implementation @@ -134,7 +137,7 @@ basic_string_view::type, dy // to_string() allow (explicit) conversions from string_view to string // template -std::basic_string::type> to_string(const basic_string_view& view) +std::basic_string::type> to_string(basic_string_view view) { return{ view.data(), view.length() }; } @@ -161,7 +164,7 @@ public: size_type length() const { return sv_.length(); } pointer assume0() const { return data(); } - string_view_type ensure_z() const { return Guide::ensure_z(sv_); } + string_view_type ensure_z() const { return gsl::ensure_z(sv_); } iterator begin() const { return sv_.begin(); } iterator end() const { return sv_.end(); } @@ -176,3 +179,5 @@ using zstring_builder = basic_zstring_builder; template using wzstring_builder = basic_zstring_builder; } + +#endif // GSL_STRING_VIEW_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index afe24a3..5e4c395 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,6 @@ -cmake_minimum_required(VERSION 3.2.2) +cmake_minimum_required(VERSION 2.8.7) -project(GSLTests) +project(GSLTests CXX) add_subdirectory(unittest-cpp) @@ -9,7 +9,7 @@ include_directories( ./unittest-cpp ) -add_definitions(-DSAFER_CPP_TESTING) +add_definitions(-DGSL_THROWS_FOR_TESTING) if(MSVC14 OR MSVC12) # has the support we need # remove unnecessary warnings about unchecked iterators @@ -23,7 +23,7 @@ else() elseif(COMPILER_SUPPORTS_CXX11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") else() - message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") + message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") endif() endif() @@ -31,128 +31,23 @@ 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() -add_executable(array_view_tests - array_view_tests.cpp -) -target_link_libraries(array_view_tests - UnitTest++ -) -install(TARGETS array_view_tests - RUNTIME DESTINATION bin -) -add_test( - NAME array_view_tests - COMMAND array_view_tests -) +function(add_gsl_test name) + add_executable(${name} ${name}.cpp) + target_link_libraries(${name} UnitTest++) + install(TARGETS ${name} + RUNTIME DESTINATION bin + ) + add_test( + ${name} + ${name} + ) +endfunction() -add_executable(string_view_tests - string_view_tests.cpp -) -target_link_libraries(string_view_tests - UnitTest++ -) -install(TARGETS string_view_tests - RUNTIME DESTINATION bin -) -add_test( - NAME string_view_tests - COMMAND string_view_tests -) - -add_executable(at_tests - at_tests.cpp -) -target_link_libraries(at_tests - UnitTest++ -) -install(TARGETS at_tests - RUNTIME DESTINATION bin -) -add_test( - NAME at_tests - COMMAND at_tests -) - -add_executable(bounds_tests - bounds_tests.cpp -) -target_link_libraries(bounds_tests - UnitTest++ -) -install(TARGETS bounds_tests - RUNTIME DESTINATION bin -) -add_test( - NAME bounds_tests - COMMAND bounds_tests -) - -add_executable(maybenull_tests - maybenull_tests.cpp -) -target_link_libraries(maybenull_tests - UnitTest++ -) -install(TARGETS maybenull_tests - RUNTIME DESTINATION bin -) -add_test( - NAME maybenull_tests - COMMAND maybenull_tests -) - -add_executable(notnull_tests - notnull_tests.cpp -) -target_link_libraries(notnull_tests - UnitTest++ -) -install(TARGETS notnull_tests - RUNTIME DESTINATION bin -) -add_test( - NAME notnull_tests - COMMAND notnull_tests -) - -add_executable(assertion_tests - assertion_tests.cpp -) -target_link_libraries(assertion_tests - UnitTest++ -) -install(TARGETS assertion_tests - RUNTIME DESTINATION bin -) -add_test( - NAME assertion_tests - COMMAND assertion_tests -) - -add_executable(utils_tests - utils_tests.cpp -) -target_link_libraries(utils_tests - UnitTest++ -) -install(TARGETS utils_tests - RUNTIME DESTINATION bin -) -add_test( - NAME utils_tests - COMMAND utils_tests -) - -add_executable(owner_tests - owner_tests.cpp -) -target_link_libraries(owner_tests - UnitTest++ -) -install(TARGETS owner_tests - RUNTIME DESTINATION bin -) -add_test( - NAME owner_tests - COMMAND owner_tests -) +add_gsl_test(array_view_tests) +add_gsl_test(string_view_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) diff --git a/tests/array_view_tests.cpp b/tests/array_view_tests.cpp index ba251e8..3a8acc2 100644 --- a/tests/array_view_tests.cpp +++ b/tests/array_view_tests.cpp @@ -16,18 +16,14 @@ #include #include -#include -#include + #include #include #include #include -#include -#include - using namespace std; -using namespace Guide; +using namespace gsl; namespace { @@ -261,8 +257,8 @@ SUITE(array_view_tests) int a[30][4][5]; auto av = as_array_view(a); - auto sub = av.section({15, 0, 0}, Guide::index<3>{2, 2, 2}); - auto subsub = sub.section({1, 0, 0}, Guide::index<3>{1, 1, 1}); + 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}); } TEST(array_view_section) @@ -554,7 +550,7 @@ SUITE(array_view_tests) { // zero stride - strided_array_view sav{ av, {{4}, {}} }; + strided_array_view sav{ av,{ { 4 },{} } }; CHECK(sav[0] == 0); CHECK(sav[3] == 0); CHECK_THROW(sav[4], fail_fast); @@ -562,7 +558,7 @@ SUITE(array_view_tests) { // zero extent - strided_array_view sav{ av,{ {},{1} } }; + strided_array_view sav{ av,{ {},{ 1 } } }; CHECK_THROW(sav[0], fail_fast); } @@ -635,27 +631,17 @@ SUITE(array_view_tests) strided_array_view sav5{ av.as_array_view(dim<2>(), dim<2>()), { 1 } }; strided_array_view sav6{ av.as_array_view(dim<2>(), dim<2>()), { 1,1,1 } }; strided_array_view sav7{ av.as_array_view(dim<2>(), dim<2>()), { { 1,1 },{ 1,1 },{ 1,1 } } }; - } -#endif - - { - // stride initializer list size should match the rank of the array - CHECK_THROW((index<1>{ 0,1 }), fail_fast); - CHECK_THROW((strided_array_view{ arr, {1, {1,1}} }), fail_fast); -#ifdef _MSC_VER - CHECK_THROW((strided_array_view{ arr, {{1,1 }, {1,1}} }), fail_fast); -#endif - CHECK_THROW((strided_array_view{ av, {1, {1,1}} }), fail_fast); -#ifdef _MSC_VER - CHECK_THROW((strided_array_view{ av, {{1,1 }, {1,1}} }), fail_fast); -#endif - CHECK_THROW((strided_array_view{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1}} }), fail_fast); - CHECK_THROW((strided_array_view{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1,1,1}} }), fail_fast); -#ifdef _MSC_VER - CHECK_THROW((strided_array_view{ av.as_array_view(dim<2>(), dim<2>()), {{1,1,1}, {1}} }), fail_fast); -#endif - } + index<1> index{ 0, 1 }; + strided_array_view sav8{ arr,{ 1,{ 1,1 } } }; + strided_array_view sav9{ arr,{ { 1,1 },{ 1,1 } } }; + strided_array_view sav10{ av,{ 1,{ 1,1 } } }; + strided_array_view sav11{ av,{ { 1,1 },{ 1,1 } } }; + strided_array_view sav12{ av.as_array_view(dim<2>(), dim<2>()),{ { 1 },{ 1 } } }; + strided_array_view sav13{ av.as_array_view(dim<2>(), dim<2>()),{ { 1 },{ 1,1,1 } } }; + strided_array_view sav14{ av.as_array_view(dim<2>(), dim<2>()),{ { 1,1,1 },{ 1 } } }; + } +#endif } TEST(strided_array_view_type_conversion) @@ -839,6 +825,94 @@ SUITE(array_view_tests) delete[] arr; } + TEST(index_constructors) + { + { + // components of the same type + index<3> i1(0, 1, 2); + CHECK(i1[0] == 0); + + // components of different types + size_t c0 = 0; + size_t c1 = 1; + index<3> i2(c0, c1, 2); + CHECK(i2[0] == 0); + + // from array + index<3> i3 = { 0,1,2 }; + CHECK(i3[0] == 0); + + // from other index of the same size type + index<3> i4 = i3; + CHECK(i4[0] == 0); + + // from other index of bigger size type + index<3, short> i5 = i4; + CHECK(i5[0] == 0); + + // from other index of smaller size type + index<3, long long> i6 = i4; + CHECK(i6[0] == 0); + + // default + index<3, long long> i7; + CHECK(i7[0] == 0); + + // default + index<3, long long> i9 = {}; + CHECK(i9[0] == 0); + } + + { + // components of the same type + index<1> i1(0); + CHECK(i1[0] == 0); + + // components of different types + size_t c0 = 0; + index<1> i2(c0); + CHECK(i2[0] == 0); + + // from array + index<1> i3 = { 0 }; + CHECK(i3[0] == 0); + + // from int + index<1> i4 = 0; + CHECK(i4[0] == 0); + + // from other index of the same size type + index<1> i5 = i3; + CHECK(i5[0] == 0); + + // from other index of bigger size type + index<1, short> i6 = i5; + CHECK(i6[0] == 0); + + // from other index of smaller size type + index<1, long long> i7 = i6; + CHECK(i7[0] == 0); + + // default + index<1, long long> i8; + CHECK(i8[0] == 0); + + // default + index<1, long long> i9 = {}; + CHECK(i9[0] == 0); + } + +#ifdef CONFIRM_COMPILATION_ERRORS + { + index<3> i1(0, 1); + index<3> i2(0, 1, 2, 3); + index<3> i3 = { 0 }; + index<3> i4 = { 0, 1, 2, 3 }; + index<1> i5 = { 0,1 }; + } +#endif + } + TEST(index_operations) { size_t a[3] = { 0, 1, 2 }; @@ -873,7 +947,18 @@ SUITE(array_view_tests) } { - index<2> k = index<2>::shift_left(i); + index<3> k = 3 * i; + + CHECK(i[0] == 0); + CHECK(i[1] == 1); + CHECK(i[2] == 2); + CHECK(k[0] == 0); + CHECK(k[1] == 3); + CHECK(k[2] == 6); + } + + { + index<2> k = details::shift_left(i); CHECK(i[0] == 0); CHECK(i[1] == 1); @@ -914,11 +999,35 @@ SUITE(array_view_tests) } } - size_t idx = 0; - for (auto num : section) + size_t check_sum = 0; + for (size_t i = 0; i < length; ++i) { - CHECK(num == av[idx][1]); - idx++; + check_sum += av[i][1]; + } + + { + size_t idx = 0; + size_t sum = 0; + for (auto num : section) + { + CHECK(num == av[idx][1]); + sum += num; + idx++; + } + + CHECK(sum == check_sum); + } + { + size_t idx = length - 1; + size_t sum = 0; + for (auto iter = section.rbegin(); iter != section.rend(); ++iter) + { + CHECK(*iter == av[idx][1]); + sum += *iter; + idx--; + } + + CHECK(sum == check_sum); } } @@ -989,7 +1098,7 @@ SUITE(array_view_tests) auto bounds = strided_bounds<1>({ length }, { 2 }); #else auto bounds = strided_bounds<1>(index<1>{ length }, index<1>{ 2 }); -#endif +#endif strided_array_view strided(&av.data()[1], av.size() - 1, bounds); CHECK(strided.size() == length); @@ -1050,7 +1159,7 @@ SUITE(array_view_tests) for (unsigned int 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]); + CHECK(section[idx] == expected[2 * i + 2 * j + k]); } } @@ -1168,6 +1277,152 @@ SUITE(array_view_tests) } + template + index Convert(index index) + { + return{ index }; + } + + TEST(DomainConverters) + { + // to smaller + { + index<2, int> int_index{ 0,1 }; + index<2, short> short_index{ int_index }; + + CHECK(short_index[0] == 0); + CHECK(short_index[1] == 1); + } + + // to smaller (failure) + { + index<2, int> big_int_index{ std::numeric_limits::max(), 1 }; + CHECK_THROW((Convert<2,int, short int>(big_int_index)), fail_fast); + } + + // to same, sign mismatch + { + index<2, int> int_index{ 0,1 }; + index<2, unsigned int> uint_index{ int_index }; + + CHECK(uint_index[0] == 0); + CHECK(uint_index[1] == 1); + } + + // to same, sign mismatch, reversed + { + index<2, unsigned int> uint_index{ 0,1 }; + index<2, int> int_index{ uint_index }; + + CHECK(int_index[0] == 0); + CHECK(int_index[1] == 1); + } + + // to smaller, sign mismatch + { + index<2, int> int_index{ 0,1 }; + index<2, unsigned short> ushort_index{ int_index }; + + CHECK(ushort_index[0] == 0); + CHECK(ushort_index[1] == 1); + } + + // to bigger + { + index<2, int> int_index{ 0,1 }; + index<2, long long> longlong_index{ int_index }; + + CHECK(longlong_index[0] == 0); + CHECK(longlong_index[1] == 1); + } + + // to bigger with max index + { + index<2, int> big_int_index{ std::numeric_limits::max(), 1 }; + index<2, long long> longlong_index{ big_int_index }; + + CHECK(longlong_index[0] == std::numeric_limits::max()); + CHECK(longlong_index[1] == 1); + } + + // to bigger, sign mismatch + { + index<2, int> int_index{ 0,1 }; + index<2, unsigned long long> ulonglong_index{ int_index }; + + CHECK(ulonglong_index[0] == 0); + CHECK(ulonglong_index[1] == 1); + } + + } + + TEST(DomainConvertersRank1) + { + // to smaller + { + index<1, int> int_index{ 0 }; + index<1, short> short_index{ int_index }; + + CHECK(short_index[0] == 0); + } + + // to smaller (failure) + { + index<1, int> big_int_index{ std::numeric_limits::max() }; + + CHECK_THROW((Convert<1, int, short int>(big_int_index)), fail_fast); + } + + // to same, sign mismatch + { + index<1, int> int_index{ 0 }; + index<1, unsigned int> uint_index{ int_index }; + + CHECK(uint_index[0] == 0); + } + + // to same, sign mismatch, reversed + { + index<1, unsigned int> uint_index{ 0 }; + index<1, int> int_index{ uint_index }; + + CHECK(int_index[0] == 0); + } + + // to smaller, sign mismatch + { + index<1, int> int_index{ 0 }; + index<1, unsigned short> ushort_index{ int_index }; + + CHECK(ushort_index[0] == 0); + } + + // to bigger + { + index<1, int> int_index{ 0 }; + index<1, long long> longlong_index{ int_index }; + + CHECK(longlong_index[0] == 0); + } + + // to bigger with max index + { + index<1, int> big_int_index{ std::numeric_limits::max() }; + index<1, long long> longlong_index{ big_int_index }; + + CHECK(longlong_index[0] == std::numeric_limits::max()); + } + + // to bigger, sign mismatch + { + index<1, int> int_index{ 0 }; + index<1, unsigned long long> ulonglong_index{ int_index }; + + CHECK(ulonglong_index[0] == 0); + } + + } + TEST(constructors) { array_view av(nullptr); @@ -1531,7 +1786,7 @@ SUITE(array_view_tests) CHECK_THROW(f(), fail_fast); } - TEST(AsWriteableBytes) + TEST(AsWriteableBytes) { int a[] = { 1, 2, 3, 4 }; @@ -1557,7 +1812,36 @@ SUITE(array_view_tests) CHECK(wav.data() == (byte*)&a[0]); CHECK(wav.length() == sizeof(a)); } + } + TEST(NonConstIterator) + { + int a[] = { 1, 2, 3, 4 }; + + { + array_view av = a; + auto wav = av.as_writeable_bytes(); + for (auto& b : wav) + { + b = byte(0); + } + for (size_t i = 0; i < 4; ++i) + { + CHECK(a[i] == 0); + } + } + + { + array_view av = a; + for (auto& n : av) + { + n = 1; + } + for (size_t i = 0; i < 4; ++i) + { + CHECK(a[i] == 1); + } + } } TEST(ArrayViewComparison) diff --git a/tests/assertion_tests.cpp b/tests/assertion_tests.cpp index 012a043..acd381a 100644 --- a/tests/assertion_tests.cpp +++ b/tests/assertion_tests.cpp @@ -17,7 +17,7 @@ #include #include -using namespace Guide; +using namespace gsl; SUITE(assertion_tests) { diff --git a/tests/at_tests.cpp b/tests/at_tests.cpp index 6a86307..d27dd9d 100644 --- a/tests/at_tests.cpp +++ b/tests/at_tests.cpp @@ -19,7 +19,7 @@ #include using namespace std; -using namespace Guide; +using namespace gsl; SUITE(at_tests) { diff --git a/tests/bounds_tests.cpp b/tests/bounds_tests.cpp index b14a113..c3f549f 100644 --- a/tests/bounds_tests.cpp +++ b/tests/bounds_tests.cpp @@ -19,7 +19,7 @@ #include using namespace std; -using namespace Guide;; +using namespace gsl;; namespace { diff --git a/tests/maybenull_tests.cpp b/tests/maybenull_tests.cpp deleted file mode 100644 index 1fdfb78..0000000 --- a/tests/maybenull_tests.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -// 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 -#include - -using namespace Guide; - -struct MyBase { bool foo() { return true; } }; -struct MyDerived : public MyBase {}; -struct Unrelated {}; - -SUITE(MaybeNullTests) -{ - TEST(TestMaybeNull1) - { - int n = 5; - maybe_null_dbg opt_n(&n); - int result = 0; - bool threw = false; - - CHECK_THROW(result = *opt_n, fail_fast); - } - - TEST(TestMaybeNull2) - { - int n = 5; - maybe_null opt_n(&n); - int result = 0; - if (opt_n.present()) - result = *opt_n; - } - - TEST(TestMaybeNull3) - { - int n = 5; - maybe_null opt_n(&n); - int result = 0; - if (opt_n != nullptr) - result = *opt_n; - } - - int test4_helper(maybe_null p) - { - if (p != nullptr) - return *p; - return -1; - } - - TEST(TestMaybeNull4) - { - int n = 5; - int result = 0; - result = test4_helper(&n); - } - - int test5_helper(maybe_null_dbg p) - { - return *p; - } - - TEST(TestMaybeNull5) - { - int n = 5; - int result = 0; - bool threw = false; - - CHECK_THROW(result = test5_helper(&n), fail_fast); - } - -#ifdef CONFIRM_COMPILATION_ERRORS - int TestMaybeNull6() - { - int n; - maybe_null o(n); - } -#endif - - int g_int; - void test7_helper(maybe_null *> outptr) - { - g_int = 5; - - if (outptr.present()) - *outptr = &g_int; - } - - void test7b_helper(maybe_null_dbg *> outptr) - { - g_int = 5; - - if (outptr.present()) - *outptr = &g_int; - } - - TEST(TestMaybeNull7a) - { - maybe_null outval; - test7_helper(&outval); - CHECK(outval.present() && *outval == 5); - } - - TEST(TestMaybeNull7b) - { - maybe_null_dbg outval; - test7b_helper(&outval); - CHECK_THROW((void)*outval, fail_fast); - } - - int test8_helper1(maybe_null_dbg opt) - { - return *opt; - } - - int test8_helper2a(maybe_null_dbg opt) - { - if (!opt.present()) - return 0; - return test8_helper1(opt); - } - - TEST(TestMaybeNull8a) - { - int n = 5; - maybe_null_dbg opt(&n); - CHECK_THROW(test8_helper2a(opt), fail_fast); - } - -#ifdef CONVERT_TO_PTR_TO_CONST - int test9_helper(maybe_null copt) - { - if (copt.present()) - return *copt; - return 0; - } - - void TestMaybeNull9() - { - int n = 5; - maybe_null opt(&n); - CHECK_THROW(test9_helper(opt), fail_fast); - } -#endif - - TEST(TestMaybeNullCasting) - { - MyDerived derived; - maybe_null p = &derived; - CHECK(p.present()); - - maybe_null q = p; - CHECK(q == p); - -#ifdef CONFIRM_COMPILATION_ERRORS - maybe_null r = p; - maybe_null s = reinterpret_cast(p); -#endif - maybe_null_dbg t = reinterpret_cast(p.get()); - - CHECK_THROW((void)(void*)t.get(), fail_fast); - maybe_null_dbg u = reinterpret_cast(p.get()); - CHECK(u.present()); - CHECK((void*)p.get() == (void*)u.get()); - } - - TEST(TestMaybeNullArrow) - { - MyDerived derived; - maybe_null_dbg p = &derived; - - CHECK_THROW(p->foo(), fail_fast); - CHECK(p.present()); - CHECK(p->foo()); - - maybe_null q = p; - CHECK(q.present()); - CHECK(q->foo()); - } -} - -int main(int, const char *[]) -{ - return UnitTest::RunAllTests(); -} diff --git a/tests/notnull_tests.cpp b/tests/notnull_tests.cpp index 008cbb3..a9624b8 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -16,8 +16,9 @@ #include #include +#include -using namespace Guide; +using namespace gsl; struct MyBase {}; struct MyDerived : public MyBase {}; @@ -48,21 +49,35 @@ SUITE(NotNullTests) not_null p; // yay...does not compile! std::unique_ptr up = std::make_unique(120); not_null p = up; + + // Forbid non-nullptr assignable types + not_null> f(std::vector{1}); + not_null z(10); + not_null> y({1,2}); #endif int i = 12; auto rp = RefCounted(&i); not_null p(rp); CHECK(p.get() == &i); + + not_null> x(std::make_shared(10)); // shared_ptr is nullptr assignable } TEST(TestNotNullCasting) { - MyDerived derived; + MyBase base; + MyDerived derived; + Unrelated unrelated; + not_null u = &unrelated; not_null p = &derived; - not_null q = p; + not_null q = &base; + q = p; // allowed with heterogeneous copy ctor CHECK(q == p); #ifdef CONFIRM_COMPILATION_ERRORS + q = u; // no viable conversion possible between MyBase* and Unrelated* + p = q; // not possible to implicitly convert MyBase* to MyDerived* + not_null r = p; not_null s = reinterpret_cast(p); #endif diff --git a/tests/owner_tests.cpp b/tests/owner_tests.cpp index 430b31a..47c223a 100644 --- a/tests/owner_tests.cpp +++ b/tests/owner_tests.cpp @@ -18,7 +18,7 @@ #include #include -using namespace Guide; +using namespace gsl; SUITE(owner_tests) { @@ -33,6 +33,7 @@ SUITE(owner_tests) CHECK(*p == 120); f(p); CHECK(*p == 121); + delete p; } } diff --git a/tests/string_view_tests.cpp b/tests/string_view_tests.cpp index c382cf0..e553ccd 100644 --- a/tests/string_view_tests.cpp +++ b/tests/string_view_tests.cpp @@ -20,7 +20,7 @@ #include using namespace std; -using namespace Guide; +using namespace gsl; SUITE(string_view_tests) { @@ -45,7 +45,7 @@ SUITE(string_view_tests) TEST(TestConstructFromStdVector) { - std::vector vec('h', 5); + std::vector vec(5, 'h'); string_view<> v = vec; CHECK(v.length() == vec.size()); } @@ -79,6 +79,14 @@ SUITE(string_view_tests) } } + TEST(TestConstructFromConstCharPointer) + { + const char* s = "Hello"; + cstring_view<> v = ensure_z(s); + CHECK(v.length() == 5); + CHECK(v.used_length() == v.length()); + } + TEST(TestConversionToConst) { char stack_string[] = "Hello"; diff --git a/tests/utils_tests.cpp b/tests/utils_tests.cpp index 0dc4809..9406e6b 100644 --- a/tests/utils_tests.cpp +++ b/tests/utils_tests.cpp @@ -18,7 +18,7 @@ #include #include -using namespace Guide; +using namespace gsl; SUITE(utils_tests) { @@ -37,6 +37,25 @@ SUITE(utils_tests) 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;