Merge pull request #1 from Microsoft/master

Update from original
This commit is contained in:
Zachary Henkel 2015-11-04 11:05:46 -06:00
commit 05da162b37
20 changed files with 1123 additions and 1326 deletions

21
.clang-format Normal file
View File

@ -0,0 +1,21 @@
ColumnLimit: 100
UseTab: Never
IndentWidth: 4
AccessModifierOffset: -4
NamespaceIndentation: Inner
BreakBeforeBraces: Allman
AlwaysBreakTemplateDeclarations: true
BreakConstructorInitializersBeforeComma: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
AllowShortBlocksOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
PointerAlignment: Left
AlignConsecutiveAssignments: false
AlignTrailingComments: false
SpaceAfterCStyleCast: true

13
.gitignore vendored
View File

@ -1 +1,14 @@
tests/unittest-cpp tests/unittest-cpp
CMakeFiles
tests/CMakeFiles
tests/Debug
*.opensdf
*.sdf
tests/*tests.dir
*.vcxproj
*.vcxproj.filters
*.sln
*.tlog
Testing/Temporary/*.*
CMakeCache.txt
*.suo

68
.travis.yml Normal file
View File

@ -0,0 +1,68 @@
# Based on https://github.com/ldionne/hana/blob/master/.travis.yml
language: cpp
sudo: false
matrix:
include:
- env: COMPILER=clang++-3.6 BUILD_TYPE=Debug CLANG=1
compiler: clang
addons: &clang36
apt:
packages:
- clang-3.6
- cmake
- g++-5
sources: &sources
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.6
- kalakris-cmake
- env: COMPILER=clang++-3.6 BUILD_TYPE=Release CLANG=1
compiler: clang
addons: *clang36
- env: COMPILER=g++-5 BUILD_TYPE=Debug
compiler: gcc
addons: &gcc5
apt:
packages: g++-5
sources: *sources
- env: COMPILER=g++-5 BUILD_TYPE=Release
compiler: gcc
addons: *gcc5
install:
- which $COMPILER
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
- mkdir ${DEPS_DIR} && cd ${DEPS_DIR}
- |
if [[ "$CLANG" == 1 && "${TRAVIS_OS_NAME}" == "linux" && "${STDLIB}" != "libstdc++" ]]; then
if [[ "${COMPILER}" == "clang++-3.5" ]]; then LLVM_VERSION="3.5.2"; fi
if [[ "${COMPILER}" == "clang++-3.6" ]]; then LLVM_VERSION="3.6.2"; fi
if [[ "${COMPILER}" == "clang++-3.7" ]]; then LLVM_VERSION="3.7.0"; fi
LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz"
LIBCXX_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxx-${LLVM_VERSION}.src.tar.xz"
LIBCXXABI_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxxabi-${LLVM_VERSION}.src.tar.xz"
mkdir -p llvm llvm/build llvm/projects/libcxx llvm/projects/libcxxabi
travis_retry wget --quiet -O - ${LLVM_URL} | tar --strip-components=1 -xJ -C llvm
travis_retry wget --quiet -O - ${LIBCXX_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxx
travis_retry wget --quiet -O - ${LIBCXXABI_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxxabi
(cd llvm/build && cmake .. -DCMAKE_INSTALL_PREFIX=${DEPS_DIR}/llvm/install -DCMAKE_CXX_COMPILER=clang++)
(cd llvm/build/projects/libcxx && make install -j2)
(cd llvm/build/projects/libcxxabi && make install -j2)
export CXXFLAGS="-I ${DEPS_DIR}/llvm/install/include/c++/v1"
export LDFLAGS="-L ${DEPS_DIR}/llvm/install/lib -l c++ -l c++abi"
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${DEPS_DIR}/llvm/install/lib"
fi
before_script:
- cd ${TRAVIS_BUILD_DIR}
- git clone --depth 1 https://github.com/Microsoft/unittest-cpp tests/unittest-cpp
- cmake -H. -Bb -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_INSTALL_PREFIX=$PWD/o -DCMAKE_BUILD_TYPE=$BUILD_TYPE
- cmake --build b
script:
- cd b
- ctest
notifications:
email: false

View File

@ -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( include_directories(
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}

View File

@ -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. [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 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. a PR, please post a comment in the associated issue to avoid duplication of effort.
## Legal ## Legal

View File

@ -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 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). [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, tracking Microsoft's fork of the Guidelines. Microsoft's fork can be found here: This repo contains Microsoft's implementation of GSL.
[C++ Core Guidelines](https://github.com/Microsoft/CppCoreGuidelines).
The library includes types like `array_view<>`, `string_view<>`, `owner<>` and others. The library includes types like `array_view<>`, `string_view<>`, `owner<>` and others.
@ -25,8 +24,9 @@ The test suite that exercises GSL has been built and passes successfully on the
* Windows using GCC 5.1 * Windows using GCC 5.1
* GNU/Linux using Clang/LLVM 3.6 * GNU/Linux using Clang/LLVM 3.6
* GNU/Linux using GCC 5.1 * GNU/Linux using GCC 5.1
* Mac OS Yosemite using XCode with AppleClang 7.0.0.7000072 * OS X Yosemite using Xcode with AppleClang 7.0.0.7000072
* Mac OS Yosemite using GCC-5.2.0 * 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 > 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. contributing any changes that were necessary back to this project to benefit the wider community.
@ -34,7 +34,7 @@ contributing any changes that were necessary back to this project to benefit the
## Building the tests ## Building the tests
To build the tests, you will require the following: 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 * [UnitTest-cpp](https://github.com/Microsoft/unittest-cpp), to be cloned under the [tests/unittest-cpp](./tests/unittest-cpp) directory
of your GSL source. of your GSL source.

File diff suppressed because it is too large Load Diff

View File

@ -16,16 +16,23 @@
#pragma once #pragma once
#ifndef GSL_FAIL_FAST_H
#define GSL_FAIL_FAST_H
#include <exception> #include <exception>
namespace Guide #if defined(GSL_THROWS_FOR_TESTING)
#include <stdexcept>
#endif
namespace gsl
{ {
// //
// Having "fail fast" result in an exception makes unit testing // Having "fail fast" result in an exception makes unit testing
// the GSL classes that rely upon it much simpler. // 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 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) { if (!cond) std::terminate(); }
inline void fail_fast_assert(bool cond, const char* const) { 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

View File

@ -16,11 +16,42 @@
#pragma once #pragma once
#ifndef GSL_GSL_H
#define GSL_GSL_H
#include "array_view.h" // array_view, strided_array_view... #include "array_view.h" // array_view, strided_array_view...
#include "string_view.h" // zstring, string_view, zstring_builder... #include "string_view.h" // zstring, string_view, zstring_builder...
#include <memory> #include <memory>
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 // GSL.assert: assertions
// //
#define Expects(x) Guide::fail_fast_assert((x)) #define Expects(x) gsl::fail_fast_assert((x))
#define Ensures(x) Guide::fail_fast_assert((x)) #define Ensures(x) gsl::fail_fast_assert((x))
// //
// GSL.util: utilities // 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 F> template <class F>
class Final_act class final_act
{ {
public: public:
explicit Final_act(F f) : f_(f) {} explicit final_act(F f) noexcept : f_(std::move(f)), invoke_(true) {}
Final_act(const Final_act&& other) : f_(other.f_) {} 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(const final_act&) = delete;
Final_act& operator=(const Final_act&) = delete; final_act& operator=(const final_act&) = delete;
~Final_act() { f_(); } ~final_act() noexcept { if (invoke_) f_(); }
private: private:
F f_; F f_;
bool invoke_;
}; };
// finally() - convenience function to generate a Final_act // finally() - convenience function to generate a final_act
template <class F> template <class F>
Final_act<F> finally(F f) { return Final_act<F>(f); } final_act<F> finally(const F &f) noexcept { return final_act<F>(f); }
template <class F>
final_act<F> finally(F &&f) noexcept { return final_act<F>(std::forward<F>(f)); }
// narrow_cast(): a searchable way to do narrowing casts of values // narrow_cast(): a searchable way to do narrowing casts of values
template<class T, class U> template<class T, class U>
T narrow_cast(U u) { return static_cast<T>(u); } T narrow_cast(U u) noexcept { return static_cast<T>(u); }
struct narrowing_error : public std::exception {}; struct narrowing_error : public std::exception {};
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value // 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 T> template<class T>
class not_null class not_null
{ {
static_assert(std::is_assignable<T&, std::nullptr_t>::value, "T cannot be assigned nullptr.");
public: public:
not_null(T t) : ptr_(t) { ensure_invariant(); } not_null(T t) : ptr_(t) { ensure_invariant(); }
not_null& operator=(const T& t) { ptr_ = t; ensure_invariant(); return *this; }
// 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(const not_null &other) = default; not_null(const not_null &other) = default;
not_null& operator=(const not_null &other) = default;
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>> template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
not_null(const not_null<U> &other) : ptr_(other.get()) not_null(const not_null<U> &other)
{ {
*this = other;
} }
not_null<T>& operator=(const T& t) { ptr_ = t; ensure_invariant(); return *this; } template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
not_null& operator=(const not_null<U> &other)
{
ptr_ = other.get();
return *this;
}
// prevents compilation when someone attempts to assign a nullptr // prevents compilation when someone attempts to assign a nullptr
not_null(std::nullptr_t) = delete;
not_null(int) = delete;
not_null<T>& operator=(std::nullptr_t) = delete; not_null<T>& operator=(std::nullptr_t) = delete;
not_null<T>& operator=(int) = delete; not_null<T>& operator=(int) = delete;
@ -153,135 +195,39 @@ private:
not_null<T>& operator-=(size_t) = delete; not_null<T>& operator-=(size_t) = delete;
}; };
} // namespace gsl
// namespace std
// maybe_null
//
// Describes an optional pointer - provides symmetry with not_null
//
template<class T>
class maybe_null_dbg
{ {
public: template<class T>
maybe_null_dbg() : ptr_(nullptr), tested_(false) {} struct hash<gsl::not_null<T>>
maybe_null_dbg(const T& p) : ptr_(p), tested_(false) {}
maybe_null_dbg(const maybe_null_dbg& rhs) : ptr_(rhs.ptr_), tested_(false) {}
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
maybe_null_dbg(const not_null<U> &other) : ptr_(other.get()), tested_(false)
{ {
} size_t operator()(const gsl::not_null<T> & value) const
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
maybe_null_dbg(const maybe_null_dbg<U> &other) : ptr_(other.get()), tested_(false)
{
}
maybe_null_dbg& operator=(const T& p)
{
if (ptr_ != p)
{ {
ptr_ = p; return hash<T>{}(value);
tested_ = false;
} }
return *this; };
}
maybe_null_dbg& operator=(const maybe_null_dbg& rhs) } // namespace std
{
if (this != &rhs)
{
ptr_ = rhs.ptr_;
tested_ = false;
}
return *this;
}
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 #ifdef _MSC_VER
__assume(ptr_ != nullptr);
#endif
return ptr_;
}
operator T() const { return get(); } #undef constexpr
T operator->() const { return get(); } #pragma pop_macro("constexpr")
private: #if _MSC_VER <= 1800
const size_t ptee_size_ = sizeof(*ptr_); // T must be a pointer type #pragma warning(pop)
// unwanted operators...pointers only point to single objects! #ifndef GSL_THROWS_FOR_TESTING
// TODO ensure all arithmetic ops on this type are unavailable #pragma undef noexcept
maybe_null_dbg<T>& operator++() = delete; #endif // GSL_THROWS_FOR_TESTING
maybe_null_dbg<T>& operator--() = delete;
maybe_null_dbg<T> operator++(int) = delete;
maybe_null_dbg<T> operator--(int) = delete;
maybe_null_dbg<T>& operator+(size_t) = delete;
maybe_null_dbg<T>& operator+=(size_t) = delete;
maybe_null_dbg<T>& operator-(size_t) = delete;
maybe_null_dbg<T>& operator-=(size_t) = delete;
T ptr_; #endif // _MSC_VER <= 1800
mutable bool tested_;
};
template<class T> #endif // _MSC_VER
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;
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>> #if defined(GSL_THROWS_FOR_TESTING)
maybe_null_ret(const not_null<U> &other) : ptr_(other.get()) #undef noexcept
{ #endif // GSL_THROWS_FOR_TESTING
}
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>> #endif // GSL_GSL_H
maybe_null_ret(const maybe_null_ret<U> &other) : ptr_(other.get())
{
}
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
maybe_null_ret(const maybe_null_dbg<U> &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<T>& operator++() = delete;
maybe_null_ret<T>& operator--() = delete;
maybe_null_ret<T> operator++(int) = delete;
maybe_null_ret<T> operator--(int) = delete;
maybe_null_ret<T>& operator+(size_t) = delete;
maybe_null_ret<T>& operator+=(size_t) = delete;
maybe_null_ret<T>& operator-(size_t) = delete;
maybe_null_ret<T>& operator-=(size_t) = delete;
const size_t ptee_size_ = sizeof(*ptr_); // T must be a pointer type
T ptr_;
};
template<class T> using maybe_null = maybe_null_ret<T>;
} // namespace Guide

View File

@ -16,10 +16,13 @@
#pragma once #pragma once
#ifndef GSL_STRING_VIEW_H
#define GSL_STRING_VIEW_H
#include "array_view.h" #include "array_view.h"
#include <cstring> #include <cstring>
namespace Guide namespace gsl
{ {
// //
// czstring and wzstring // czstring and wzstring
@ -79,9 +82,9 @@ template<class T, class SizeType, const T Sentinel>
array_view<T, dynamic_range> ensure_sentinel(const T* seq, SizeType max = std::numeric_limits<SizeType>::max()) array_view<T, dynamic_range> ensure_sentinel(const T* seq, SizeType max = std::numeric_limits<SizeType>::max())
{ {
auto cur = seq; auto cur = seq;
while ((cur - seq) < max && *cur != Sentinel) ++cur; while (SizeType(cur - seq) < max && *cur != Sentinel) ++cur;
fail_fast_assert(*cur == Sentinel); fail_fast_assert(*cur == Sentinel);
return{ seq, cur - seq }; return{ seq, SizeType(cur - seq) };
} }
@ -93,7 +96,7 @@ array_view<T, dynamic_range> ensure_sentinel(const T* seq, SizeType max = std::n
template<class T> template<class T>
inline basic_string_view<T, dynamic_range> ensure_z(T* const & sz, size_t max = std::numeric_limits<size_t>::max()) inline basic_string_view<T, dynamic_range> ensure_z(T* const & sz, size_t max = std::numeric_limits<size_t>::max())
{ {
return ensure_sentinel<0>(sz, max); return ensure_sentinel<T, size_t, 0>(sz, max);
} }
// TODO (neilmac) there is probably a better template-magic way to get the const and non-const overloads to share an implementation // 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<typename std::remove_pointer<typename Cont::pointer>::type, dy
// to_string() allow (explicit) conversions from string_view to string // to_string() allow (explicit) conversions from string_view to string
// //
template<class CharT, size_t Extent> template<class CharT, size_t Extent>
std::basic_string<typename std::remove_const<CharT>::type> to_string(const basic_string_view<CharT, Extent>& view) std::basic_string<typename std::remove_const<CharT>::type> to_string(basic_string_view<CharT, Extent> view)
{ {
return{ view.data(), view.length() }; return{ view.data(), view.length() };
} }
@ -161,7 +164,7 @@ public:
size_type length() const { return sv_.length(); } size_type length() const { return sv_.length(); }
pointer assume0() const { return data(); } 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 begin() const { return sv_.begin(); }
iterator end() const { return sv_.end(); } iterator end() const { return sv_.end(); }
@ -176,3 +179,5 @@ using zstring_builder = basic_zstring_builder<char, Max>;
template <size_t Max = dynamic_range> template <size_t Max = dynamic_range>
using wzstring_builder = basic_zstring_builder<wchar_t, Max>; using wzstring_builder = basic_zstring_builder<wchar_t, Max>;
} }
#endif // GSL_STRING_VIEW_H

View File

@ -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) add_subdirectory(unittest-cpp)
@ -9,7 +9,7 @@ include_directories(
./unittest-cpp ./unittest-cpp
) )
add_definitions(-DSAFER_CPP_TESTING) add_definitions(-DGSL_THROWS_FOR_TESTING)
if(MSVC14 OR MSVC12) # has the support we need if(MSVC14 OR MSVC12) # has the support we need
# remove unnecessary warnings about unchecked iterators # remove unnecessary warnings about unchecked iterators
@ -23,7 +23,7 @@ else()
elseif(COMPILER_SUPPORTS_CXX11) elseif(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
else() 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()
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") 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() endif()
add_executable(array_view_tests function(add_gsl_test name)
array_view_tests.cpp add_executable(${name} ${name}.cpp)
) target_link_libraries(${name} UnitTest++)
target_link_libraries(array_view_tests install(TARGETS ${name}
UnitTest++ RUNTIME DESTINATION bin
) )
install(TARGETS array_view_tests add_test(
RUNTIME DESTINATION bin ${name}
) ${name}
add_test( )
NAME array_view_tests endfunction()
COMMAND array_view_tests
)
add_executable(string_view_tests add_gsl_test(array_view_tests)
string_view_tests.cpp add_gsl_test(string_view_tests)
) add_gsl_test(at_tests)
target_link_libraries(string_view_tests add_gsl_test(bounds_tests)
UnitTest++ add_gsl_test(notnull_tests)
) add_gsl_test(assertion_tests)
install(TARGETS string_view_tests add_gsl_test(utils_tests)
RUNTIME DESTINATION bin add_gsl_test(owner_tests)
)
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
)

View File

@ -16,18 +16,14 @@
#include <UnitTest++/UnitTest++.h> #include <UnitTest++/UnitTest++.h>
#include <array_view.h> #include <array_view.h>
#include <numeric>
#include <array>
#include <string> #include <string>
#include <vector> #include <vector>
#include <list> #include <list>
#include <iostream> #include <iostream>
#include <functional>
#include <algorithm>
using namespace std; using namespace std;
using namespace Guide; using namespace gsl;
namespace namespace
{ {
@ -261,8 +257,8 @@ SUITE(array_view_tests)
int a[30][4][5]; int a[30][4][5];
auto av = as_array_view(a); auto av = as_array_view(a);
auto sub = av.section({15, 0, 0}, Guide::index<3>{2, 2, 2}); auto sub = av.section({15, 0, 0}, gsl::index<3>{2, 2, 2});
auto subsub = sub.section({1, 0, 0}, Guide::index<3>{1, 1, 1}); auto subsub = sub.section({1, 0, 0}, gsl::index<3>{1, 1, 1});
} }
TEST(array_view_section) TEST(array_view_section)
@ -554,7 +550,7 @@ SUITE(array_view_tests)
{ {
// zero stride // zero stride
strided_array_view<int, 1> sav{ av, {{4}, {}} }; strided_array_view<int, 1> sav{ av,{ { 4 },{} } };
CHECK(sav[0] == 0); CHECK(sav[0] == 0);
CHECK(sav[3] == 0); CHECK(sav[3] == 0);
CHECK_THROW(sav[4], fail_fast); CHECK_THROW(sav[4], fail_fast);
@ -562,7 +558,7 @@ SUITE(array_view_tests)
{ {
// zero extent // zero extent
strided_array_view<int, 1> sav{ av,{ {},{1} } }; strided_array_view<int, 1> sav{ av,{ {},{ 1 } } };
CHECK_THROW(sav[0], fail_fast); CHECK_THROW(sav[0], fail_fast);
} }
@ -635,27 +631,17 @@ SUITE(array_view_tests)
strided_array_view<int, 2> sav5{ av.as_array_view(dim<2>(), dim<2>()), { 1 } }; strided_array_view<int, 2> sav5{ av.as_array_view(dim<2>(), dim<2>()), { 1 } };
strided_array_view<int, 2> sav6{ av.as_array_view(dim<2>(), dim<2>()), { 1,1,1 } }; strided_array_view<int, 2> sav6{ av.as_array_view(dim<2>(), dim<2>()), { 1,1,1 } };
strided_array_view<int, 2> sav7{ av.as_array_view(dim<2>(), dim<2>()), { { 1,1 },{ 1,1 },{ 1,1 } } }; strided_array_view<int, 2> sav7{ av.as_array_view(dim<2>(), dim<2>()), { { 1,1 },{ 1,1 },{ 1,1 } } };
index<1> index{ 0, 1 };
strided_array_view<int, 1> sav8{ arr,{ 1,{ 1,1 } } };
strided_array_view<int, 1> sav9{ arr,{ { 1,1 },{ 1,1 } } };
strided_array_view<int, 1> sav10{ av,{ 1,{ 1,1 } } };
strided_array_view<int, 1> sav11{ av,{ { 1,1 },{ 1,1 } } };
strided_array_view<int, 2> sav12{ av.as_array_view(dim<2>(), dim<2>()),{ { 1 },{ 1 } } };
strided_array_view<int, 2> sav13{ av.as_array_view(dim<2>(), dim<2>()),{ { 1 },{ 1,1,1 } } };
strided_array_view<int, 2> sav14{ av.as_array_view(dim<2>(), dim<2>()),{ { 1,1,1 },{ 1 } } };
} }
#endif #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<int, 1>{ arr, {1, {1,1}} }), fail_fast);
#ifdef _MSC_VER
CHECK_THROW((strided_array_view<int, 1>{ arr, {{1,1 }, {1,1}} }), fail_fast);
#endif
CHECK_THROW((strided_array_view<int, 1>{ av, {1, {1,1}} }), fail_fast);
#ifdef _MSC_VER
CHECK_THROW((strided_array_view<int, 1>{ av, {{1,1 }, {1,1}} }), fail_fast);
#endif
CHECK_THROW((strided_array_view<int, 2>{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1}} }), fail_fast);
CHECK_THROW((strided_array_view<int, 2>{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1,1,1}} }), fail_fast);
#ifdef _MSC_VER
CHECK_THROW((strided_array_view<int, 2>{ av.as_array_view(dim<2>(), dim<2>()), {{1,1,1}, {1}} }), fail_fast);
#endif
}
} }
TEST(strided_array_view_type_conversion) TEST(strided_array_view_type_conversion)
@ -839,6 +825,94 @@ SUITE(array_view_tests)
delete[] arr; 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) TEST(index_operations)
{ {
size_t a[3] = { 0, 1, 2 }; 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[0] == 0);
CHECK(i[1] == 1); CHECK(i[1] == 1);
@ -914,11 +999,35 @@ SUITE(array_view_tests)
} }
} }
size_t idx = 0; size_t check_sum = 0;
for (auto num : section) for (size_t i = 0; i < length; ++i)
{ {
CHECK(num == av[idx][1]); check_sum += av[i][1];
idx++; }
{
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);
} }
} }
@ -1168,6 +1277,152 @@ SUITE(array_view_tests)
} }
template<size_t Rank, typename T1, typename T2>
index<Rank, T2> Convert(index<Rank, T1> 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<int>::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<int>::max(), 1 };
index<2, long long> longlong_index{ big_int_index };
CHECK(longlong_index[0] == std::numeric_limits<int>::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<int>::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<int>::max() };
index<1, long long> longlong_index{ big_int_index };
CHECK(longlong_index[0] == std::numeric_limits<int>::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) TEST(constructors)
{ {
array_view<int, dynamic_range> av(nullptr); array_view<int, dynamic_range> av(nullptr);
@ -1557,7 +1812,36 @@ SUITE(array_view_tests)
CHECK(wav.data() == (byte*)&a[0]); CHECK(wav.data() == (byte*)&a[0]);
CHECK(wav.length() == sizeof(a)); CHECK(wav.length() == sizeof(a));
} }
}
TEST(NonConstIterator)
{
int a[] = { 1, 2, 3, 4 };
{
array_view<int, dynamic_range> 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<int, dynamic_range> av = a;
for (auto& n : av)
{
n = 1;
}
for (size_t i = 0; i < 4; ++i)
{
CHECK(a[i] == 1);
}
}
} }
TEST(ArrayViewComparison) TEST(ArrayViewComparison)

View File

@ -17,7 +17,7 @@
#include <UnitTest++/UnitTest++.h> #include <UnitTest++/UnitTest++.h>
#include <gsl.h> #include <gsl.h>
using namespace Guide; using namespace gsl;
SUITE(assertion_tests) SUITE(assertion_tests)
{ {

View File

@ -19,7 +19,7 @@
#include <vector> #include <vector>
using namespace std; using namespace std;
using namespace Guide; using namespace gsl;
SUITE(at_tests) SUITE(at_tests)
{ {

View File

@ -19,7 +19,7 @@
#include <vector> #include <vector>
using namespace std; using namespace std;
using namespace Guide;; using namespace gsl;;
namespace namespace
{ {

View File

@ -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 <UnitTest++/UnitTest++.h>
#include <gsl.h>
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<int *> opt_n(&n);
int result = 0;
bool threw = false;
CHECK_THROW(result = *opt_n, fail_fast);
}
TEST(TestMaybeNull2)
{
int n = 5;
maybe_null<int *> opt_n(&n);
int result = 0;
if (opt_n.present())
result = *opt_n;
}
TEST(TestMaybeNull3)
{
int n = 5;
maybe_null<int *> opt_n(&n);
int result = 0;
if (opt_n != nullptr)
result = *opt_n;
}
int test4_helper(maybe_null<int *> 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<int *> 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<int> o(n);
}
#endif
int g_int;
void test7_helper(maybe_null<maybe_null<int *> *> outptr)
{
g_int = 5;
if (outptr.present())
*outptr = &g_int;
}
void test7b_helper(maybe_null_dbg<maybe_null_dbg<int *> *> outptr)
{
g_int = 5;
if (outptr.present())
*outptr = &g_int;
}
TEST(TestMaybeNull7a)
{
maybe_null<int *> outval;
test7_helper(&outval);
CHECK(outval.present() && *outval == 5);
}
TEST(TestMaybeNull7b)
{
maybe_null_dbg<int *> outval;
test7b_helper(&outval);
CHECK_THROW((void)*outval, fail_fast);
}
int test8_helper1(maybe_null_dbg<int *> opt)
{
return *opt;
}
int test8_helper2a(maybe_null_dbg<int *> opt)
{
if (!opt.present())
return 0;
return test8_helper1(opt);
}
TEST(TestMaybeNull8a)
{
int n = 5;
maybe_null_dbg<int *> opt(&n);
CHECK_THROW(test8_helper2a(opt), fail_fast);
}
#ifdef CONVERT_TO_PTR_TO_CONST
int test9_helper(maybe_null<const int *> copt)
{
if (copt.present())
return *copt;
return 0;
}
void TestMaybeNull9()
{
int n = 5;
maybe_null<int *> opt(&n);
CHECK_THROW(test9_helper(opt), fail_fast);
}
#endif
TEST(TestMaybeNullCasting)
{
MyDerived derived;
maybe_null<MyDerived*> p = &derived;
CHECK(p.present());
maybe_null<MyBase*> q = p;
CHECK(q == p);
#ifdef CONFIRM_COMPILATION_ERRORS
maybe_null<Unrelated*> r = p;
maybe_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
#endif
maybe_null_dbg<Unrelated*> t = reinterpret_cast<Unrelated*>(p.get());
CHECK_THROW((void)(void*)t.get(), fail_fast);
maybe_null_dbg<Unrelated*> u = reinterpret_cast<Unrelated*>(p.get());
CHECK(u.present());
CHECK((void*)p.get() == (void*)u.get());
}
TEST(TestMaybeNullArrow)
{
MyDerived derived;
maybe_null_dbg<MyDerived*> p = &derived;
CHECK_THROW(p->foo(), fail_fast);
CHECK(p.present());
CHECK(p->foo());
maybe_null<MyBase*> q = p;
CHECK(q.present());
CHECK(q->foo());
}
}
int main(int, const char *[])
{
return UnitTest::RunAllTests();
}

View File

@ -16,8 +16,9 @@
#include <UnitTest++/UnitTest++.h> #include <UnitTest++/UnitTest++.h>
#include <gsl.h> #include <gsl.h>
#include <vector>
using namespace Guide; using namespace gsl;
struct MyBase {}; struct MyBase {};
struct MyDerived : public MyBase {}; struct MyDerived : public MyBase {};
@ -48,21 +49,35 @@ SUITE(NotNullTests)
not_null<int*> p; // yay...does not compile! not_null<int*> p; // yay...does not compile!
std::unique_ptr<int> up = std::make_unique<int>(120); std::unique_ptr<int> up = std::make_unique<int>(120);
not_null<int*> p = up; not_null<int*> p = up;
// Forbid non-nullptr assignable types
not_null<std::vector<int>> f(std::vector<int>{1});
not_null<int> z(10);
not_null<std::vector<int>> y({1,2});
#endif #endif
int i = 12; int i = 12;
auto rp = RefCounted<int>(&i); auto rp = RefCounted<int>(&i);
not_null<int*> p(rp); not_null<int*> p(rp);
CHECK(p.get() == &i); CHECK(p.get() == &i);
not_null<std::shared_ptr<int>> x(std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
} }
TEST(TestNotNullCasting) TEST(TestNotNullCasting)
{ {
MyDerived derived; MyBase base;
MyDerived derived;
Unrelated unrelated;
not_null<Unrelated*> u = &unrelated;
not_null<MyDerived*> p = &derived; not_null<MyDerived*> p = &derived;
not_null<MyBase*> q = p; not_null<MyBase*> q = &base;
q = p; // allowed with heterogeneous copy ctor
CHECK(q == p); CHECK(q == p);
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
q = u; // no viable conversion possible between MyBase* and Unrelated*
p = q; // not possible to implicitly convert MyBase* to MyDerived*
not_null<Unrelated*> r = p; not_null<Unrelated*> r = p;
not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p); not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
#endif #endif

View File

@ -18,7 +18,7 @@
#include <gsl.h> #include <gsl.h>
#include <functional> #include <functional>
using namespace Guide; using namespace gsl;
SUITE(owner_tests) SUITE(owner_tests)
{ {
@ -33,6 +33,7 @@ SUITE(owner_tests)
CHECK(*p == 120); CHECK(*p == 120);
f(p); f(p);
CHECK(*p == 121); CHECK(*p == 121);
delete p;
} }
} }

View File

@ -20,7 +20,7 @@
#include <cstdlib> #include <cstdlib>
using namespace std; using namespace std;
using namespace Guide; using namespace gsl;
SUITE(string_view_tests) SUITE(string_view_tests)
{ {
@ -45,7 +45,7 @@ SUITE(string_view_tests)
TEST(TestConstructFromStdVector) TEST(TestConstructFromStdVector)
{ {
std::vector<char> vec('h', 5); std::vector<char> vec(5, 'h');
string_view<> v = vec; string_view<> v = vec;
CHECK(v.length() == vec.size()); 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) TEST(TestConversionToConst)
{ {
char stack_string[] = "Hello"; char stack_string[] = "Hello";

View File

@ -18,7 +18,7 @@
#include <gsl.h> #include <gsl.h>
#include <functional> #include <functional>
using namespace Guide; using namespace gsl;
SUITE(utils_tests) SUITE(utils_tests)
{ {
@ -37,6 +37,25 @@ SUITE(utils_tests)
CHECK(i == 1); 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) TEST(finally_function_with_bind)
{ {
int i = 0; int i = 0;