Initial commit of library files.

This commit is contained in:
Neil MacIntosh 2015-08-20 18:09:14 -07:00
parent 8368329142
commit a9dcbe04ff
17 changed files with 4177 additions and 2 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
tests/unittest-cpp

11
CMakeLists.txt Normal file
View File

@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.2.2)
project(GSL)
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
)
enable_testing()
add_subdirectory(tests)

11
LICENSE Normal file
View File

@ -0,0 +1,11 @@
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.

View File

@ -1,2 +1,62 @@
# GSL
Guidelines Support Library
# GSL: Guidelines Support Library
This library contains functions and types that are suggested for use by the
[C++ Coding Guidelines](https://github.com/Microsoft/CppCodingStandards/).
These include types like `array_view<>`, `string_view<>`, `owner<>` and others.
The entire implementation is provided inline in the headers under the [include](./include) directory.
While some types have been broken out into their own headers (e.g. [include/array_view.h](./include/array_view.h)),
it is simplest to just include [gsl.h](./include/gsl.h) and gain access to the entire library.
> NOTE: We encourage contributions that improve or refine any of the types in this library.
# Quick Start
## Supported Platforms
The test suite that exercises GSL has been built and passes successfully on the following platforms:
* Windows using Visual Studio 2013
* Windows using Visual Studio 2015
* Windows using Clang\LLVM 3.6
* Windows using GCC 5.1
* Linux using Clang\LLVM 3.6
* Linux using GCC 5.1
> If you successfully port GSL to another platform, we would love to hear from you. 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.
* [UnitTest-cpp](https://github.com/Microsoft/unittest-cpp), to be cloned under the [tests/unittest-cpp](./tests/unittest-cpp) directory
of your GSL source.
These steps assume the source code of this repository has been cloned into a directory named `c:\GSL`.
1. Create a directory to contain the build outputs for a particular architecture (we name it c:\GSL\vs14-x86 in this example).
cd GSL
md build-x86
cd build-x86
2. Configure CMake to use the compiler of your choice (you can see a list by running `cmake --help`).
cmake -G "Visual Studio 14 2015" c:\GSL
3. Build the test suite (in this case, in the Debug configuration, Release is another good choice).
cmake --build . --config Debug
4. Run the test suite.
ctest -C Debug
All tests should pass - indicating your platform is fully supported and you are ready to use the GSL types!
## Using the libraries
As the types are entirely implemented inline in headers, there are no linking requirements.
Just place the contents of the [include](./include) directory within your source tree so it is available
to your compiler, then include the appropriate headers in your program, and away you go!

2113
include/array_view.h Normal file

File diff suppressed because it is too large Load Diff

39
include/fail_fast.h Normal file
View File

@ -0,0 +1,39 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include <exception>
namespace Guide
{
//
// Having "fail fast" result in an exception makes unit testing
// the GSL classes that rely upon it much simpler.
//
#if defined(SAFER_CPP_TESTING)
struct fail_fast : public std::exception {};
inline void fail_fast_assert(bool cond) { if (!cond) throw fail_fast(); }
#else
inline void fail_fast_assert(bool cond) { if (!cond) std::terminate(); }
#endif // SAFER_CPP_TESTING
}

284
include/gsl.h Normal file
View File

@ -0,0 +1,284 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "array_view.h" // array_view, strided_array_view...
#include "string_view.h" // zstring, string_view, zstring_builder...
#include <memory>
namespace Guide
{
//
// GSL.owner: ownership pointers
//
using std::unique_ptr;
using std::shared_ptr;
//
// GSL.assert: assertions
//
#define Expects(x) Guide::fail_fast_assert((x))
#define Ensures(x) Guide::fail_fast_assert((x))
//
// GSL.util: utilities
//
// Final_act allows you to ensure something gets run at the end of a scope
template <class F>
class Final_act
{
public:
explicit Final_act(F f) : 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_(); }
private:
F f_;
};
// finally() - convenience function to generate a Final_act
template <class F>
Final_act<F> finally(F f) { return Final_act<F>(f); }
// narrow_cast(): a searchable way to do narrowing casts of values
template<class T, class U>
T narrow_cast(U u) { return static_cast<T>(u); }
struct narrowing_error : public std::exception {};
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
template<class T, class U>
T narrow(U u) { T t = narrow_cast<T>(u); if (static_cast<U>(t) != u) throw narrowing_error(); return t; }
//
// at() - Bounds-checked way of accessing static arrays, std::array, std::vector
//
template <class T, size_t N>
T& at(T(&arr)[N], size_t index) { fail_fast_assert(index < N); return arr[index]; }
template <class T, size_t N>
T& at(std::array<T, N>& arr, size_t index) { fail_fast_assert(index < N); return arr[index]; }
template <class Cont>
typename Cont::value_type& at(Cont& cont, size_t index) { fail_fast_assert(index < cont.size()); return cont[index]; }
//
// not_null
//
// Restricts a pointer or smart pointer to only hold non-null values.
//
// Has zero size overhead over T.
//
// If T is a pointer (i.e. T == U*) then
// - allow construction from U* or U&
// - disallow construction from nullptr_t
// - disallow default construction
// - ensure construction from U* fails with nullptr
// - allow implicit conversion to U*
//
template<class T>
class not_null
{
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(const not_null &other) = default;
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
not_null(const not_null<U> &other) : ptr_(other.get())
{
}
not_null<T>& operator=(const T& t) { ptr_ = t; ensure_invariant(); return *this; }
// prevents compilation when someone attempts to assign a nullptr
not_null<T>& operator=(std::nullptr_t) = delete;
not_null<T>& operator=(int) = delete;
T get() const {
#ifdef _MSC_VER
__assume(ptr_ != nullptr);
#endif
return ptr_;
} // the assume() should help the optimizer
operator T() const { return get(); }
T operator->() const { return get(); }
bool operator==(const T& rhs) const { return ptr_ == rhs; }
bool operator!=(const T& rhs) const { return !(*this == rhs); }
private:
T ptr_;
// we assume that the compiler can hoist/prove away most of the checks inlined from this function
// if not, we could make them optional via conditional compilation
void ensure_invariant() const { fail_fast_assert(ptr_ != nullptr); }
// unwanted operators...pointers only point to single objects!
// TODO ensure all arithmetic ops on this type are unavailable
not_null<T>& operator++() = delete;
not_null<T>& operator--() = delete;
not_null<T> operator++(int) = delete;
not_null<T> operator--(int) = delete;
not_null<T>& operator+(size_t) = delete;
not_null<T>& operator+=(size_t) = delete;
not_null<T>& operator-(size_t) = delete;
not_null<T>& operator-=(size_t) = delete;
};
//
// maybe_null
//
// Describes an optional pointer - provides symmetry with not_null
//
template<class T>
class maybe_null_dbg
{
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 <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)
{
}
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;
tested_ = false;
}
return *this;
}
maybe_null_dbg& operator=(const maybe_null_dbg& rhs)
{
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
__assume(ptr_ != nullptr);
#endif
return ptr_;
}
operator T() const { return get(); }
T operator->() const { return get(); }
private:
const size_t ptee_size_ = sizeof(*ptr_); // T must be a pointer type
// unwanted operators...pointers only point to single objects!
// TODO ensure all arithmetic ops on this type are unavailable
maybe_null_dbg<T>& operator++() = delete;
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_;
mutable bool tested_;
};
template<class T>
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>>
maybe_null_ret(const not_null<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_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

178
include/string_view.h Normal file
View File

@ -0,0 +1,178 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "array_view.h"
#include <cstring>
namespace Guide
{
//
// czstring and wzstring
//
// These are "tag" typedef's for C-style strings (i.e. null-terminated character arrays)
// that allow static analysis to help find bugs.
//
// There are no additional features/semantics that we can find a way to add inside the
// type system for these types that will not either incur significant runtime costs or
// (sometimes needlessly) break existing programs when introduced.
//
template<size_t Max = dynamic_range>
using czstring = const char*;
template<size_t Max = dynamic_range>
using cwzstring = const wchar_t*;
template<size_t Max = dynamic_range>
using zstring = char*;
template<size_t Max = dynamic_range>
using wzstring = wchar_t*;
//
// string_view and relatives
//
// Note that Extent is always single-dimension only
// Note that SizeType is defaulted to be smaller than size_t which is the array_view default
//
// TODO (neilmac) once array_view regains configurable size_type, update these typedef's
//
template <class CharT, size_t Extent = dynamic_range>
using basic_string_view = array_view<CharT, Extent>;
template<size_t Extent = dynamic_range>
using string_view = basic_string_view<char, Extent>;
template<size_t Extent = dynamic_range>
using cstring_view = basic_string_view<const char, Extent>;
template<size_t Extent = dynamic_range>
using wstring_view = basic_string_view<wchar_t, Extent>;
template<size_t Extent = dynamic_range>
using cwstring_view = basic_string_view<const wchar_t, Extent>;
//
// ensure_sentinel()
//
// Provides a way to obtain an array_view from a contiguous sequence
// that ends with a (non-inclusive) sentinel value.
//
// Will fail-fast if sentinel cannot be found before max elements are examined.
//
template<class T, class SizeType, const T Sentinel>
array_view<T, dynamic_range> ensure_sentinel(const T* seq, SizeType max = std::numeric_limits<SizeType>::max())
{
auto cur = seq;
while ((cur - seq) < max && *cur != Sentinel) ++cur;
fail_fast_assert(*cur == Sentinel);
return{ seq, cur - seq };
}
//
// ensure_z - creates a string_view for a czstring or cwzstring.
// Will fail fast if a null-terminator cannot be found before
// the limit of size_type.
//
template<class T>
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);
}
// TODO (neilmac) there is probably a better template-magic way to get the const and non-const overloads to share an implementation
inline basic_string_view<char, dynamic_range> ensure_z(char* const & sz, size_t max)
{
auto len = strnlen(sz, max);
fail_fast_assert(sz[len] == 0); return{ sz, len };
}
inline basic_string_view<const char, dynamic_range> ensure_z(const char* const& sz, size_t max)
{
auto len = strnlen(sz, max);
fail_fast_assert(sz[len] == 0); return{ sz, len };
}
inline basic_string_view<wchar_t, dynamic_range> ensure_z(wchar_t* const & sz, size_t max)
{
auto len = wcsnlen(sz, max);
fail_fast_assert(sz[len] == 0); return{ sz, len };
}
inline basic_string_view<const wchar_t, dynamic_range> ensure_z(const wchar_t* const & sz, size_t max)
{
auto len = wcsnlen(sz, max);
fail_fast_assert(sz[len] == 0); return{ sz, len };
}
template<class T, size_t N>
basic_string_view<T, dynamic_range> ensure_z(T(&sz)[N]) { return ensure_z(&sz[0], N); }
template<class Cont>
basic_string_view<typename std::remove_pointer<typename Cont::pointer>::type, dynamic_range> ensure_z(Cont& cont)
{
return ensure_z(cont.data(), cont.length());
}
//
// to_string() allow (explicit) conversions from string_view to string
//
template<class CharT, size_t Extent>
std::basic_string<typename std::remove_const<CharT>::type> to_string(const basic_string_view<CharT, Extent>& view)
{
return{ view.data(), view.length() };
}
template<class CharT, size_t Extent = dynamic_range>
class basic_zstring_builder
{
public:
using string_view_type = basic_string_view<CharT, Extent>;
using value_type = CharT;
using pointer = CharT*;
using size_type = typename string_view_type::size_type;
using iterator = typename string_view_type::iterator;
basic_zstring_builder(CharT* data, size_type length) : sv_(data, length) {}
template<size_t Size>
basic_zstring_builder(CharT(&arr)[Size]) : sv_(arr) {}
pointer data() const { return sv_.data(); }
string_view_type view() const { return sv_; }
size_type length() const { return sv_.length(); }
pointer assume0() const { return data(); }
string_view_type ensure_z() const { return Guide::ensure_z(sv_); }
iterator begin() const { return sv_.begin(); }
iterator end() const { return sv_.end(); }
private:
string_view_type sv_;
};
template <size_t Max = dynamic_range>
using zstring_builder = basic_zstring_builder<char, Max>;
template <size_t Max = dynamic_range>
using wzstring_builder = basic_zstring_builder<wchar_t, Max>;
}

143
tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,143 @@
cmake_minimum_required(VERSION 3.2.2)
project(GSLTests)
add_subdirectory(unittest-cpp)
include_directories(
../include
./unittest-cpp
)
add_definitions(-DSAFER_CPP_TESTING)
if(MSVC14 OR MSVC12)
# has the support we need
else()
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
if(COMPILER_SUPPORTS_CXX14)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
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.")
endif()
endif()
if (NOT EXISTS tests/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
)
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
)

648
tests/array_view_tests.cpp Normal file
View File

@ -0,0 +1,648 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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 <array_view.h>
#include <numeric>
#include <array>
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <functional>
#include <algorithm>
using namespace std;
using namespace Guide;
namespace
{
void use(int&) {}
struct BaseClass {};
struct DerivedClass : BaseClass {};
}
SUITE(array_view_tests)
{
TEST(basics)
{
auto ptr = as_array_view(new int[10], 10);
fill(ptr.begin(), ptr.end(), 99);
for (int num : ptr)
{
CHECK(num == 99);
}
delete[] ptr.data();
static_bounds<size_t, 4, dynamic_range, 2> bounds{ 3 };
#ifdef CONFIRM_COMPILATION_ERRORS
array_view<int, 4, dynamic_range, 2> av(nullptr, bounds);
av.extent();
av.extent<2>();
av[8][4][3];
#endif
}
TEST (array_view_convertible)
{
#ifdef CONFIRM_COMPILATION_ERRORS
array_view<int, 7, 4, 2> av1(nullptr, b1);
#endif
auto f = [&]() { array_view<int, 7, 4, 2> av1(nullptr); };
CHECK_THROW(f(), fail_fast);
array_view<int, 7, dynamic_range, 2> av1(nullptr);
#ifdef CONFIRM_COMPILATION_ERRORS
static_bounds<size_t, 7, dynamic_range, 2> b12(b11);
b12 = b11;
b11 = b12;
array_view<int, dynamic_range> av1 = nullptr;
array_view<int, 7, dynamic_range, 2> av2(av1);
array_view<int, 7, 4, 2> av2(av1);
#endif
array_view<DerivedClass> avd;
#ifdef CONFIRM_COMPILATION_ERRORS
array_view<BaseClass> avb = avd;
#endif
array_view<const DerivedClass> avcd = avd;
}
TEST(boundary_checks)
{
int arr[10][2];
auto av = as_array_view(arr);
fill(begin(av), end(av), 0);
av[2][0] = 1;
av[1][1] = 3;
// out of bounds
CHECK_THROW(av[1][3] = 3, fail_fast);
CHECK_THROW((av[{1, 3}] = 3), fail_fast);
CHECK_THROW(av[10][2], fail_fast);
CHECK_THROW((av[{10,2}]), fail_fast);
}
void overloaded_func(array_view<const int, dynamic_range, 3, 5> exp, int expected_value) {
for (auto val : exp)
{
CHECK(val == expected_value);
}
}
void overloaded_func(array_view<const char, dynamic_range, 3, 5> exp, char expected_value) {
for (auto val : exp)
{
CHECK(val == expected_value);
}
}
void fixed_func(array_view<int, 3, 3, 5> exp, int expected_value) {
for (auto val : exp)
{
CHECK(val == expected_value);
}
}
TEST(array_view_parameter_test)
{
auto data = new int[4][3][5];
auto av = as_array_view(data, 4);
CHECK(av.size() == 60);
fill(av.begin(), av.end(), 34);
int count = 0;
for_each(av.rbegin(), av.rend(), [&](int val) { count += val; });
CHECK(count == 34 * 60);
overloaded_func(av, 34);
overloaded_func(av.as_array_view(dim<>(4), dim<>(3), dim<>(5)), 34);
//fixed_func(av, 34);
delete[] data;
}
TEST(md_access)
{
unsigned int width = 5, height = 20;
unsigned int imgSize = width * height;
auto image_ptr = new int[imgSize][3];
// size check will be done
auto image_view = as_array_view(image_ptr, imgSize).as_array_view(dim<>(height), dim<>(width), dim<3>());
iota(image_view.begin(), image_view.end(), 1);
int expected = 0;
for (unsigned int i = 0; i < height; i++)
{
for (unsigned int j = 0; j < width; j++)
{
CHECK(expected + 1 == image_view[i][j][0]);
CHECK(expected + 2 == image_view[i][j][1]);
CHECK(expected + 3 == image_view[i][j][2]);
auto val = image_view[{i, j, 0}];
CHECK(expected + 1 == val);
val = image_view[{i, j, 1}];
CHECK(expected + 2 == val);
val = image_view[{i, j, 2}];
CHECK(expected + 3 == val);
expected += 3;
}
}
}
TEST(array_view_factory_test)
{
{
int * arr = new int[150];
auto av = as_array_view(arr, dim<10>(), dim<>(3), dim<5>());
fill(av.begin(), av.end(), 24);
overloaded_func(av, 24);
delete[] arr;
array<int, 15> stdarr{ 0 };
auto av2 = as_array_view(stdarr);
overloaded_func(av2.as_array_view(dim<>(1), dim<3>(), dim<5>()), 0);
string str = "ttttttttttttttt"; // size = 15
auto t = str.data();
auto av3 = as_array_view(str);
overloaded_func(av3.as_array_view(dim<>(1), dim<3>(), dim<5>()), 't');
}
{
int a[3][4][5];
auto av = as_array_view(a);
const int (*b)[4][5];
b = a;
auto bv = as_array_view(b, 3);
CHECK(av == bv);
const std::array<double, 3> arr = {0.0, 0.0, 0.0};
auto cv = as_array_view(arr);
vector<float> vec(3);
auto dv = as_array_view(vec);
#ifdef CONFIRM_COMPILATION_ERRORS
auto dv2 = as_array_view(std::move(vec));
#endif
}
}
TEST (array_view_reshape_test)
{
int a[3][4][5];
auto av = as_array_view(a);
auto av2 = av.as_array_view(dim<60>());
auto av3 = av2.as_array_view(dim<3>(), dim<4>(), dim<5>());
auto av4 = av3.as_array_view(dim<4>(), dim<>(3), dim<5>());
auto av5 = av4.as_array_view(dim<3>(), dim<4>(), dim<5>());
auto av6 = av5.as_array_view(dim<12>(), dim<>(5));
fill(av6.begin(), av6.end(), 1);
auto av7 = av6.as_bytes();
auto av8 = av7.as_array_view<int>();
CHECK(av8.size() == av6.size());
for (size_t i = 0; i < av8.size(); i++)
{
CHECK(av8[i] == 1);
}
#ifdef CONFIRM_COMPILATION_ERRORS
struct Foo {char c[11];};
auto av9 = av7.as_array_view<Foo>();
#endif
}
TEST (array_view_section_test)
{
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});
}
TEST(constructors)
{
array_view<int, dynamic_range> av(nullptr);
CHECK(av.length() == 0);
array_view<int, dynamic_range> av2;
CHECK(av2.length() == 0);
array_view<int, dynamic_range> av3(nullptr, 0);
CHECK(av3.length() == 0);
// Constructing from a nullptr + length is specifically disallowed
auto f = [&]() {array_view<int, dynamic_range> av4(nullptr, 2);};
CHECK_THROW(f(), fail_fast);
int arr1[2][3];
array_view<int, 2, dynamic_range> av5(arr1);
array<int, 15> arr2;
array_view<int, 15> av6(arr2);
vector<int> vec1(19);
array_view<int> av7(vec1);
CHECK(av7.length() == 19);
array_view<int> av8;
CHECK(av8.length() == 0);
array_view<int> av9(arr2);
CHECK(av9.length() == 15);
#ifdef CONFIRM_COMPILATION_ERRORS
array_view<int, 4> av10;
DerivedClass *p = nullptr;
array_view<BaseClass> av11(p, 0);
#endif
}
TEST(copyandassignment)
{
array_view<int, dynamic_range> av1;
int arr[] = {3, 4, 5};
av1 = arr;
array_view<array_view_options<const int, unsigned char>, dynamic_range> av2;
av2 = av1;
}
TEST(array_view_first)
{
int arr[5] = { 1, 2, 3, 4, 5 };
{
array_view<int, 5> av = arr;
CHECK((av.first<2>().bounds() == static_bounds<size_t, 2>()));
CHECK(av.first<2>().length() == 2);
CHECK(av.first(2).length() == 2);
}
{
array_view<int, 5> av = arr;
CHECK((av.first<0>().bounds() == static_bounds<size_t, 0>()));
CHECK(av.first<0>().length() == 0);
CHECK(av.first(0).length() == 0);
}
{
array_view<int, 5> av = arr;
CHECK((av.first<5>().bounds() == static_bounds<size_t, 5>()));
CHECK(av.first<5>().length() == 5);
CHECK(av.first(5).length() == 5);
}
{
array_view<int, 5> av = arr;
#ifdef CONFIRM_COMPILATION_ERRORS
CHECK(av.first<6>().bounds() == static_bounds<size_t, 6>());
CHECK(av.first<6>().length() == 6);
#endif
CHECK_THROW(av.first(6).length(), fail_fast);
}
{
array_view<int, dynamic_range> av;
CHECK((av.first<0>().bounds() == static_bounds<size_t, 0>()));
CHECK(av.first<0>().length() == 0);
CHECK(av.first(0).length() == 0);
}
}
TEST(array_view_last)
{
int arr[5] = { 1, 2, 3, 4, 5 };
{
array_view<int, 5> av = arr;
CHECK((av.last<2>().bounds() == static_bounds<size_t, 2>()));
CHECK(av.last<2>().length() == 2);
CHECK(av.last(2).length() == 2);
}
{
array_view<int, 5> av = arr;
CHECK((av.last<0>().bounds() == static_bounds<size_t, 0>()));
CHECK(av.last<0>().length() == 0);
CHECK(av.last(0).length() == 0);
}
{
array_view<int, 5> av = arr;
CHECK((av.last<5>().bounds() == static_bounds<size_t, 5>()));
CHECK(av.last<5>().length() == 5);
CHECK(av.last(5).length() == 5);
}
{
array_view<int, 5> av = arr;
#ifdef CONFIRM_COMPILATION_ERRORS
CHECK((av.last<6>().bounds() == static_bounds<size_t, 6>()));
CHECK(av.last<6>().length() == 6);
#endif
CHECK_THROW(av.last(6).length(), fail_fast);
}
{
array_view<int, dynamic_range> av;
CHECK((av.last<0>().bounds() == static_bounds<size_t, 0>()));
CHECK(av.last<0>().length() == 0);
CHECK(av.last(0).length() == 0);
}
}
TEST(custmized_array_view_size)
{
double (*arr)[3][4] = new double[100][3][4];
array_view<array_view_options<double, char>, dynamic_range, 3, 4> av1(arr, (char)10);
struct EffectiveStructure
{
double* v1;
char v2;
};
CHECK(sizeof(av1) == sizeof(EffectiveStructure));
CHECK_THROW(av1[10][3][4], fail_fast);
array_view<const double, dynamic_range, 6, 4> av2 = av1.as_array_view(dim<>(5), dim<6>(), dim<4>());
}
TEST(array_view_sub)
{
int arr[5] = { 1, 2, 3, 4, 5 };
{
array_view<int, 5> av = arr;
CHECK((av.sub<2,2>().bounds() == static_bounds<size_t, 2>()));
CHECK((av.sub<2,2>().length() == 2));
CHECK(av.sub(2,2).length() == 2);
}
{
array_view<int, 5> av = arr;
CHECK((av.sub<0,0>().bounds() == static_bounds<size_t, 0>()));
CHECK((av.sub<0,0>().length() == 0));
CHECK(av.sub(0,0).length() == 0);
}
{
array_view<int, 5> av = arr;
CHECK((av.sub<0,5>().bounds() == static_bounds<size_t, 5>()));
CHECK((av.sub<0,5>().length() == 5));
CHECK(av.sub(0,5).length() == 5);
}
{
array_view<int, 5> av = arr;
#ifdef CONFIRM_COMPILATION_ERRORS
CHECK((av.sub<5,0>().bounds() == static_bounds<size_t, 0>()));
CHECK((av.sub<5,0>().length() == 0));
#endif
CHECK_THROW(av.sub(5,0).length(), fail_fast);
}
{
array_view<int, dynamic_range> av;
CHECK((av.sub<0,0>().bounds() == static_bounds<size_t, 0>()));
CHECK((av.sub<0,0>().length() == 0));
CHECK(av.sub(0,0).length() == 0);
}
}
void AssertNullEmptyProperties(array_view<int, dynamic_range>& av)
{
CHECK(av.length() == 0);
CHECK(av.data() == nullptr);
CHECK(!av);
}
template <class T, class U>
void AssertContentsMatch(T a1, U a2)
{
CHECK(a1.length() == a2.length());
for (size_t i = 0; i < a1.length(); ++i)
CHECK(a1[i] == a2[i]);
}
TEST(TestNullConstruction)
{
array_view<int, dynamic_range> av;
AssertNullEmptyProperties(av);
array_view<int, dynamic_range> av2(nullptr);
AssertNullEmptyProperties(av2);
}
TEST(ArrayConstruction)
{
int a[] = { 1, 2, 3, 4 };
array_view<int, dynamic_range> av = { &a[1], 3 };
CHECK(av.length() == 3);
array_view<int, dynamic_range> av3 = { a, 2 };
CHECK(av3.length() == 2);
array_view<int, dynamic_range> av2 = a;
CHECK(av2.length() == 4);
}
TEST(NonConstConstConversions)
{
int a[] = { 1, 2, 3, 4 };
#ifdef CONFIRM_COMPILATION_ERRORS
array_view<const int, dynamic_range> cav = a;
array_view<int, dynamic_range> av = cav;
#else
array_view<int, dynamic_range> av = a;
array_view<const int, dynamic_range> cav = av;
#endif
AssertContentsMatch(av, cav);
}
TEST(FixedSizeConversions)
{
int arr[] = { 1, 2, 3, 4 };
// converting to an array_view from an equal size array is ok
array_view<int, 4> av4 = arr;
CHECK(av4.length() == 4);
// converting to dynamic_range a_v is always ok
{
array_view<int, dynamic_range> av = av4;
}
{
array_view<int, dynamic_range> av = arr;
}
// initialization or assignment to static array_view that REDUCES size is NOT ok
#ifdef CONFIRM_COMPILATION_ERRORS
{
array_view<int, 2> av2 = arr;
}
{
array_view<int, 2> av2 = av4;
}
#endif
{
array_view<int, dynamic_range> av = arr;
array_view<int, 2> av2 = av;
}
#ifdef CONFIRM_COMPILATION_ERRORS
{
array_view<int, dynamic_range> av = arr;
array_view<int, 2, 1> av2 = av.as_array_view(dim<2>(), dim<2>());
}
#endif
{
array_view<int, dynamic_range> av = arr;
auto f = [&]() {array_view<int, 2, 1> av2 = av.as_array_view(dim<>(2), dim<>(2));};
CHECK_THROW(f(), fail_fast);
}
// but doing so explicitly is ok
// you can convert statically
{
array_view<int, 2> av2 = {arr, 2};
}
{
array_view<int, 1> av2 = av4.first<1>();
}
// ...or dynamically
{
// NB: implicit conversion to array_view<int,2> from array_view<int,dynamic_range>
array_view<int, 1> av2 = av4.first(1);
}
// initialization or assignment to static array_view that requires size INCREASE is not ok.
int arr2[2] = { 1, 2 };
#ifdef CONFIRM_COMPILATION_ERRORS
{
array_view<int, 4> av4 = arr2;
}
{
array_view<int, 2> av2 = arr2;
array_view<int, 4> av4 = av2;
}
#endif
{
auto f = [&]() {array_view<int, 4> av4 = {arr2, 2};};
CHECK_THROW(f(), fail_fast);
}
// this should fail - we are trying to assign a small dynamic a_v to a fixed_size larger one
array_view<int, dynamic_range> av = arr2;
auto f = [&](){ array_view<int, 4> av2 = av; };
CHECK_THROW(f(), fail_fast);
}
TEST(AsWriteableBytes)
{
int a[] = { 1, 2, 3, 4 };
{
#ifdef CONFIRM_COMPILATION_ERRORS
// you should not be able to get writeable bytes for const objects
array_view<const int, dynamic_range> av = a;
auto wav = av.as_writeable_bytes();
#endif
}
{
array_view<int, dynamic_range> av;
auto wav = av.as_writeable_bytes();
CHECK(wav.length() == av.length());
CHECK(wav.length() == 0);
CHECK(wav.bytes() == 0);
}
{
array_view<int, dynamic_range> av = a;
auto wav = av.as_writeable_bytes();
CHECK(wav.data() == (byte*)&a[0]);
CHECK(wav.length() == sizeof(a));
}
}
TEST(ArrayViewComparison)
{
int arr[10][2];
auto av1 = as_array_view(arr);
array_view<const int, dynamic_range, 2> av2 = av1;
CHECK(av1 == av2);
array_view<array_view_options<int, char>, 20> av3 = av1.as_array_view(dim<>(20));
CHECK(av3 == av2 && av3 == av1);
}
}
int main(int, const char *[])
{
return UnitTest::RunAllTests();
}

53
tests/assertion_tests.cpp Normal file
View File

@ -0,0 +1,53 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#include <UnitTest++/UnitTest++.h>
#include <gsl.h>
using namespace Guide;
SUITE(assertion_tests)
{
int f(int i)
{
Expects(i > 0 && i < 10);
return i;
}
TEST(expects)
{
CHECK(f(2) == 2);
CHECK_THROW(f(10), fail_fast);
}
int g(int i)
{
i++;
Ensures(i > 0 && i < 10);
return i;
}
TEST(ensures)
{
CHECK(g(2) == 3);
CHECK_THROW(g(9), fail_fast);
}
}
int main(int, const char *[])
{
return UnitTest::RunAllTests();
}

60
tests/at_tests.cpp Normal file
View File

@ -0,0 +1,60 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#include <UnitTest++/UnitTest++.h>
#include <gsl.h>
#include <vector>
using namespace std;
using namespace Guide;
SUITE(at_tests)
{
TEST(static_array)
{
int a[] = { 1, 2, 3, 4 };
for (int i = 0; i < 4; ++i)
CHECK(at(a, i) == i+1);
CHECK_THROW(at(a, 4), fail_fast);
}
TEST(std_array)
{
std::array<int,4> a = { 1, 2, 3, 4 };
for (int i = 0; i < 4; ++i)
CHECK(at(a, i) == i+1);
CHECK_THROW(at(a, 4), fail_fast);
}
TEST(StdVector)
{
std::vector<int> a = { 1, 2, 3, 4 };
for (int i = 0; i < 4; ++i)
CHECK(at(a, i) == i+1);
CHECK_THROW(at(a, 4), fail_fast);
}
}
int main(int, const char *[])
{
return UnitTest::RunAllTests();
}

99
tests/bounds_tests.cpp Normal file
View File

@ -0,0 +1,99 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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 <array_view.h>
#include <vector>
using namespace std;
using namespace Guide;;
namespace
{
void use(unsigned int&) {}
}
SUITE(bounds_test)
{
TEST(basic_bounds)
{
for (auto point : static_bounds <unsigned int, dynamic_range, 3, 4 > { 2 })
{
for (unsigned int j = 0; j < decltype(point)::rank; j++)
{
use(j);
use(point[j]);
}
}
}
TEST(bounds_basic)
{
static_bounds<size_t, 3, 4, 5> b;
auto a = b.slice();
static_bounds<size_t, 4, dynamic_range, 2> x{ 4 };
x.slice().slice();
}
TEST (arrayview_iterator)
{
static_bounds<size_t, 4, dynamic_range, 2> bounds{ 3 };
auto itr = bounds.begin();
#ifdef CONFIRM_COMPILATION_ERRORS
array_view< int, 4, dynamic_range, 2> av(nullptr, bounds);
auto itr2 = av.cbegin();
for (auto & v : av) {
v = 4;
}
fill(av.begin(), av.end(), 0);
#endif
}
TEST (bounds_convertible)
{
static_bounds<size_t, 7, 4, 2> b1;
static_bounds<size_t, 7, dynamic_range, 2> b2 = b1;
#ifdef CONFIRM_COMPILATION_ERRORS
static_bounds<size_t, 7, dynamic_range, 1> b4 = b2;
#endif
static_bounds<size_t, dynamic_range, dynamic_range, dynamic_range> b3 = b1;
static_bounds<int, 7, 4, 2> b4 = b3;
static_bounds<size_t, dynamic_range> b11;
static_bounds<size_t, dynamic_range> b5;
static_bounds<size_t, 34> b6;
b5 = static_bounds<size_t, 20>();
CHECK_THROW(b6 = b5, fail_fast);
b5 = static_bounds<size_t, 34>();
b6 = b5;
CHECK(b5 == b6);
CHECK(b5.size() == b6.size());
}
}
int main(int, const char *[])
{
return UnitTest::RunAllTests();
}

197
tests/maybenull_tests.cpp Normal file
View File

@ -0,0 +1,197 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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();
}

87
tests/notnull_tests.cpp Normal file
View File

@ -0,0 +1,87 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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 {};
struct MyDerived : public MyBase {};
struct Unrelated {};
// stand-in for a user-defined ref-counted class
template<typename T>
struct RefCounted
{
RefCounted(T* p) : p_(p) {}
operator T*() { return p_; }
T* p_;
};
SUITE(NotNullTests)
{
bool helper(not_null<int*> p)
{
return *p == 12;
}
TEST(TestNotNullConstructors)
{
#ifdef CONFIRM_COMPILATION_ERRORS
not_null<int*> p = nullptr; // yay...does not compile!
not_null<std::vector<char>*> p = 0; // yay...does not compile!
not_null<int*> p; // yay...does not compile!
std::unique_ptr<int> up = std::make_unique<int>(120);
not_null<int*> p = up;
#endif
int i = 12;
auto rp = RefCounted<int>(&i);
not_null<int*> p(rp);
CHECK(p.get() == &i);
}
TEST(TestNotNullCasting)
{
MyDerived derived;
not_null<MyDerived*> p = &derived;
not_null<MyBase*> q = p;
CHECK(q == p);
#ifdef CONFIRM_COMPILATION_ERRORS
not_null<Unrelated*> r = p;
not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
#endif
not_null<Unrelated*> t = reinterpret_cast<Unrelated*>(p.get());
CHECK((void*)p.get() == (void*)t.get());
}
TEST(TestNotNullAssignment)
{
int i = 12;
not_null<int*> p = &i;
CHECK(helper(p));
int* q = nullptr;
CHECK_THROW(p = q, fail_fast);
}
}
int main(int, const char *[])
{
return UnitTest::RunAllTests();
}

104
tests/string_view_tests.cpp Normal file
View File

@ -0,0 +1,104 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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 <string_view.h>
#include <vector>
#include <cstdlib>
using namespace std;
using namespace Guide;
SUITE(string_view_tests)
{
TEST(TestLiteralConstruction)
{
cwstring_view<> v = ensure_z(L"Hello");
CHECK(5 == v.length());
#ifdef CONFIRM_COMPILATION_ERRORS
wstring_view<> v2 = ensure0(L"Hello");
#endif
}
TEST(TestConstructFromStdString)
{
std::string s = "Hello there world";
cstring_view<> v = s;
CHECK(v.length() == s.length());
}
TEST(TestConstructFromStdVector)
{
std::vector<char> vec('h', 5);
string_view<> v = vec;
CHECK(v.length() == vec.size());
}
TEST(TestStackArrayConstruction)
{
wchar_t stack_string[] = L"Hello";
{
cwstring_view<> v = ensure_z(stack_string);
CHECK(v.length() == 5);
CHECK(v.used_length() == v.length());
}
{
cwstring_view<> v = stack_string;
CHECK(v.length() == 6);
CHECK(v.used_length() == v.length());
}
{
wstring_view<> v = ensure_z(stack_string);
CHECK(v.length() == 5);
CHECK(v.used_length() == v.length());
}
{
wstring_view<> v = stack_string;
CHECK(v.length() == 6);
CHECK(v.used_length() == v.length());
}
}
TEST(TestConversionToConst)
{
char stack_string[] = "Hello";
string_view<> v = ensure_z(stack_string);
cstring_view<> v2 = v;
CHECK(v.length() == v2.length());
}
TEST(TestConversionFromConst)
{
char stack_string[] = "Hello";
cstring_view<> v = ensure_z(stack_string);
#ifdef CONFIRM_COMPILATION_ERRORS
string_view<> v2 = v;
string_view<> v3 = "Hello";
#endif
}
}
int main(int, const char *[])
{
return UnitTest::RunAllTests();
}

87
tests/utils_tests.cpp Normal file
View File

@ -0,0 +1,87 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#include <UnitTest++/UnitTest++.h>
#include <gsl.h>
#include <functional>
using namespace Guide;
SUITE(utils_tests)
{
void f(int& i)
{
i += 1;
}
TEST(finally_lambda)
{
int i = 0;
{
auto _ = finally([&]() {f(i);});
CHECK(i == 0);
}
CHECK(i == 1);
}
TEST(finally_function_with_bind)
{
int i = 0;
{
auto _ = finally(std::bind(&f, std::ref(i)));
CHECK(i == 0);
}
CHECK(i == 1);
}
int j = 0;
void g() { j += 1; };
TEST(finally_function_ptr)
{
j = 0;
{
auto _ = finally(&g);
CHECK(j == 0);
}
CHECK(j == 1);
}
TEST(narrow_cast)
{
int n = 120;
char c = narrow_cast<char>(n);
CHECK(c == 120);
n = 300;
unsigned char uc = narrow_cast<unsigned char>(n);
CHECK(uc == 44);
}
TEST(narrow)
{
int n = 120;
char c = narrow<char>(n);
CHECK(c == 120);
n = 300;
CHECK_THROW(narrow<char>(n), narrowing_error);
}
}
int main(int, const char *[])
{
return UnitTest::RunAllTests();
}