Merge remote-tracking branch 'refs/remotes/Microsoft/master'

This commit is contained in:
Vladislav Yaroslavlev 2015-11-10 11:17:46 +03:00
commit 2b2adebde5
15 changed files with 2813 additions and 3401 deletions

View File

@ -1,4 +1,4 @@
ColumnLimit: 0 ColumnLimit: 100
UseTab: Never UseTab: Never
IndentWidth: 4 IndentWidth: 4
@ -6,7 +6,7 @@ AccessModifierOffset: -4
NamespaceIndentation: Inner NamespaceIndentation: Inner
BreakBeforeBraces: Allman BreakBeforeBraces: Allman
AlwaysBreakTemplateDeclarations: false AlwaysBreakTemplateDeclarations: true
BreakConstructorInitializersBeforeComma: true BreakConstructorInitializersBeforeComma: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerAllOnOneLineOrOnePerLine: true
AllowShortBlocksOnASingleLine: true AllowShortBlocksOnASingleLine: 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

View File

@ -12,6 +12,7 @@ matrix:
packages: packages:
- clang-3.6 - clang-3.6
- cmake - cmake
- g++-5
sources: &sources sources: &sources
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.6 - llvm-toolchain-precise-3.6

View File

@ -1,14 +1,14 @@
# GSL: Guidelines Support Library [![Build Status](https://travis-ci.org/Microsoft/GSL.svg?branch=master)](https://travis-ci.org/Microsoft/GSL) # 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](https://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. This repo contains Microsoft's implementation of GSL.
The library includes types like `array_view<>`, `string_view<>`, `owner<>` and others. The library includes types like `span<T>`, `string_span`, `owner<>` and others.
The entire implementation is provided inline in the headers under the [include](./include) directory. The 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)), While some types have been broken out into their own headers (e.g. [include/span.h](./include/span.h)),
it is simplest to just include [gsl.h](./include/gsl.h) and gain access to the entire library. it is simplest to just include [gsl.h](./include/gsl.h) and gain access to the entire library.
> NOTE: We encourage contributions that improve or refine any of the types in this library as well as ports to > NOTE: We encourage contributions that improve or refine any of the types in this library as well as ports to

File diff suppressed because it is too large Load Diff

View File

@ -19,8 +19,8 @@
#ifndef GSL_GSL_H #ifndef GSL_GSL_H
#define GSL_GSL_H #define GSL_GSL_H
#include "array_view.h" // array_view, strided_array_view... #include "span.h" // span, strided_span...
#include "string_view.h" // zstring, string_view, zstring_builder... #include "string_span.h" // zstring, string_span, zstring_builder...
#include <memory> #include <memory>
#ifdef _MSC_VER #ifdef _MSC_VER
@ -80,7 +80,7 @@ class final_act
public: public:
explicit final_act(F f) noexcept : f_(std::move(f)), invoke_(true) {} explicit final_act(F f) noexcept : f_(std::move(f)), invoke_(true) {}
final_act(final_act&& other) noexcept : f_(std::move(other.f_)), invoke_(true) { other.invoke_ = false; } 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;
@ -195,195 +195,21 @@ private:
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_ret;
template<class T>
class maybe_null_dbg
{
template<class U>
friend class maybe_null_dbg;
static_assert(std::is_assignable<T&, std::nullptr_t>::value, "T cannot be assigned nullptr.");
public:
maybe_null_dbg() : ptr_(nullptr), tested_(false) {}
maybe_null_dbg(std::nullptr_t) : ptr_(nullptr), tested_(false) {}
maybe_null_dbg(const T& p) : ptr_(p), tested_(false) {}
maybe_null_dbg& operator=(const T& p)
{
if (ptr_ != p)
{
ptr_ = p;
tested_ = false;
}
return *this;
}
maybe_null_dbg(const maybe_null_dbg& rhs) : ptr_(rhs.ptr_), tested_(false) {}
maybe_null_dbg& operator=(const maybe_null_dbg& rhs)
{
if (this != &rhs)
{
ptr_ = rhs.ptr_;
tested_ = false;
}
return *this;
}
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& operator=(const not_null<U> &other)
{
ptr_ = other.get();
tested_ = false;
return *this;
}
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.ptr_), tested_(false) {}
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
maybe_null_dbg& operator=(const maybe_null_dbg<U> &other)
{
ptr_ = other.ptr_;
tested_ = false;
return *this;
}
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
maybe_null_dbg(const maybe_null_ret<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& operator=(const maybe_null_ret<U> &other)
{
ptr_ = other.get();
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); }
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
bool operator==(const maybe_null_dbg<U>& rhs) const { tested_ = true; rhs.tested_ = true; return ptr_ == rhs.ptr_; }
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
bool operator!=(const maybe_null_dbg<U>& 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:
// 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
{
static_assert(std::is_assignable<T&, std::nullptr_t>::value, "T cannot be assigned nullptr.");
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& operator=(const T& p) { ptr_ = p; return *this; }
maybe_null_ret(const maybe_null_ret& rhs) = default;
maybe_null_ret& operator=(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& operator=(const not_null<U> &other)
{
ptr_ = other.get();
return *this;
}
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& operator=(const maybe_null_ret<U> &other)
{
ptr_ = other.get();
return *this;
}
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()) {}
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
maybe_null_ret& operator=(const maybe_null_dbg<U> &other)
{
ptr_ = other.get();
return *this;
}
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;
T ptr_;
};
template<class T> using maybe_null = maybe_null_ret<T>;
} // namespace gsl } // namespace gsl
namespace std
{
template<class T>
struct hash<gsl::not_null<T>>
{
size_t operator()(const gsl::not_null<T> & value) const
{
return hash<T>{}(value);
}
};
} // namespace std
#ifdef _MSC_VER #ifdef _MSC_VER
#undef constexpr #undef constexpr

1988
include/span.h Normal file

File diff suppressed because it is too large Load Diff

227
include/string_span.h Normal file
View File

@ -0,0 +1,227 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef GSL_STRING_SPAN_H
#define GSL_STRING_SPAN_H
#include "span.h"
#include <cstring>
// VS 2013 workarounds
#ifdef _MSC_VER
#if _MSC_VER <= 1800
#pragma push_macro("GSL_MSVC_HAS_TYPE_DEDUCTION_BUG")
#define GSL_MSVC_HAS_TYPE_DEDUCTION_BUG
#endif // _MSC_VER <= 1800
#endif // _MSC_VER
namespace gsl
{
//
// czstring and wzstring
//
// These are "tag" typedef's for C-style strings (i.e. null-terminated character arrays)
// that allow static analysis to help find bugs.
//
// There are no additional features/semantics that we can find a way to add inside the
// type system for these types that will not either incur significant runtime costs or
// (sometimes needlessly) break existing programs when introduced.
//
template<std::ptrdiff_t Extent = dynamic_range>
using czstring = const char*;
template<std::ptrdiff_t Extent = dynamic_range>
using cwzstring = const wchar_t*;
template<std::ptrdiff_t Extent = dynamic_range>
using zstring = char*;
template<std::ptrdiff_t Extent = dynamic_range>
using wzstring = wchar_t*;
//
// string_span and relatives
//
// Note that Extent is always single-dimension only
//
template <class CharT, std::ptrdiff_t Extent = dynamic_range>
using basic_string_span = span<CharT, Extent>;
template<std::ptrdiff_t Extent = dynamic_range>
using string_span = basic_string_span<char, Extent>;
template<std::ptrdiff_t Extent = dynamic_range>
using cstring_span = basic_string_span<const char, Extent>;
template<std::ptrdiff_t Extent = dynamic_range>
using wstring_span = basic_string_span<wchar_t, Extent>;
template<std::ptrdiff_t Extent = dynamic_range>
using cwstring_span = basic_string_span<const wchar_t, Extent>;
//
// ensure_sentinel()
//
// Provides a way to obtain an span from a contiguous sequence
// that ends with a (non-inclusive) sentinel value.
//
// Will fail-fast if sentinel cannot be found before max elements are examined.
//
template<class T, const T Sentinel>
span<T, dynamic_range> ensure_sentinel(const T* seq, std::ptrdiff_t max = PTRDIFF_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_span 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_span<T, dynamic_range> ensure_z(T* const & sz, std::ptrdiff_t max = PTRDIFF_MAX)
{
return ensure_sentinel<T, 0>(sz, max);
}
// TODO (neilmac) there is probably a better template-magic way to get the const and non-const overloads to share an implementation
inline basic_string_span<char, dynamic_range> ensure_z(char* const& sz, std::ptrdiff_t max)
{
auto len = strnlen(sz, max);
fail_fast_assert(sz[len] == 0);
return{ sz, static_cast<std::ptrdiff_t>(len) };
}
inline basic_string_span<const char, dynamic_range> ensure_z(const char* const& sz, std::ptrdiff_t max)
{
auto len = strnlen(sz, max);
fail_fast_assert(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
}
inline basic_string_span<wchar_t, dynamic_range> ensure_z(wchar_t* const& sz, std::ptrdiff_t max)
{
auto len = wcsnlen(sz, max);
fail_fast_assert(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
}
inline basic_string_span<const wchar_t, dynamic_range> ensure_z(const wchar_t* const& sz, std::ptrdiff_t max)
{
auto len = wcsnlen(sz, max);
fail_fast_assert(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
}
template<class T, size_t N>
basic_string_span<T, dynamic_range> ensure_z(T(&sz)[N]) { return ensure_z(&sz[0], static_cast<std::ptrdiff_t>(N)); }
template<class Cont>
basic_string_span<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_span to string
//
#ifndef GSL_MSVC_HAS_TYPE_DEDUCTION_BUG
template<class CharT, ptrdiff_t Extent>
std::basic_string<typename std::remove_const<CharT>::type> to_string(basic_string_span<CharT, Extent> view)
{
return{ view.data(), static_cast<size_t>(view.length()) };
}
#else
inline std::string to_string(cstring_span<> view)
{
return{ view.data(), view.length() };
}
inline std::string to_string(string_span<> view)
{
return{ view.data(), view.length() };
}
inline std::wstring to_string(cwstring_span<> view)
{
return{ view.data(), view.length() };
}
inline std::wstring to_string(wstring_span<> view)
{
return{ view.data(), view.length() };
}
#endif
template<class CharT, size_t Extent = dynamic_range>
class basic_zstring_builder
{
public:
using string_span_type = basic_string_span<CharT, Extent>;
using value_type = CharT;
using pointer = CharT*;
using size_type = typename string_span_type::size_type;
using iterator = typename string_span_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_span_type view() const { return sv_; }
size_type length() const { return sv_.length(); }
pointer assume0() const { return data(); }
string_span_type ensure_z() const { return gsl::ensure_z(sv_); }
iterator begin() const { return sv_.begin(); }
iterator end() const { return sv_.end(); }
private:
string_span_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>;
}
// VS 2013 workarounds
#ifdef _MSC_VER
#if _MSC_VER <= 1800
#pragma pop_macro("GSL_MSVC_HAS_TYPE_DEDUCTION_BUG")
#undef GSL_MSVC_HAS_TYPE_DEDUCTION_BUG
#endif // _MSC_VER <= 1800
#endif // _MSC_VER
#endif // GSL_STRING_SPAN_H

View File

@ -1,183 +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.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef GSL_STRING_VIEW_H
#define GSL_STRING_VIEW_H
#include "array_view.h"
#include <cstring>
namespace gsl
{
//
// czstring and wzstring
//
// These are "tag" typedef's for C-style strings (i.e. null-terminated character arrays)
// that allow static analysis to help find bugs.
//
// There are no additional features/semantics that we can find a way to add inside the
// type system for these types that will not either incur significant runtime costs or
// (sometimes needlessly) break existing programs when introduced.
//
template<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(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 gsl::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>;
}
#endif // GSL_STRING_VIEW_H

View File

@ -43,11 +43,10 @@ function(add_gsl_test name)
) )
endfunction() endfunction()
add_gsl_test(array_view_tests) add_gsl_test(span_tests)
add_gsl_test(string_view_tests) add_gsl_test(string_span_tests)
add_gsl_test(at_tests) add_gsl_test(at_tests)
add_gsl_test(bounds_tests) add_gsl_test(bounds_tests)
add_gsl_test(maybenull_tests)
add_gsl_test(notnull_tests) add_gsl_test(notnull_tests)
add_gsl_test(assertion_tests) add_gsl_test(assertion_tests)
add_gsl_test(utils_tests) add_gsl_test(utils_tests)

View File

@ -15,7 +15,7 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <UnitTest++/UnitTest++.h> #include <UnitTest++/UnitTest++.h>
#include <array_view.h> #include <span.h>
#include <vector> #include <vector>
using namespace std; using namespace std;
@ -23,16 +23,16 @@ using namespace gsl;;
namespace namespace
{ {
void use(unsigned int&) {} void use(std::ptrdiff_t&) {}
} }
SUITE(bounds_test) SUITE(bounds_test)
{ {
TEST(basic_bounds) TEST(basic_bounds)
{ {
for (auto point : static_bounds <unsigned int, dynamic_range, 3, 4 > { 2 }) for (auto point : static_bounds<dynamic_range, 3, 4 > { 2 })
{ {
for (unsigned int j = 0; j < decltype(point)::rank; j++) for (decltype(point)::size_type j = 0; j < decltype(point)::rank; j++)
{ {
use(j); use(j);
use(point[j]); use(point[j]);
@ -42,24 +42,24 @@ SUITE(bounds_test)
TEST(bounds_basic) TEST(bounds_basic)
{ {
static_bounds<size_t, 3, 4, 5> b; static_bounds<3, 4, 5> b;
auto a = b.slice(); auto a = b.slice();
static_bounds<size_t, 4, dynamic_range, 2> x{ 4 }; static_bounds<4, dynamic_range, 2> x{ 4 };
x.slice().slice(); x.slice().slice();
} }
TEST (arrayview_iterator) TEST (arrayview_iterator)
{ {
static_bounds<size_t, 4, dynamic_range, 2> bounds{ 3 }; static_bounds<4, dynamic_range, 2> bounds{ 3 };
auto itr = bounds.begin(); auto itr = bounds.begin();
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
array_view< int, 4, dynamic_range, 2> av(nullptr, bounds); span<int, 4, dynamic_range, 2> av(nullptr, bounds);
auto itr2 = av.cbegin(); auto itr2 = av.cbegin();
for (auto & v : av) { for (auto& v : av) {
v = 4; v = 4;
} }
fill(av.begin(), av.end(), 0); fill(av.begin(), av.end(), 0);
@ -68,24 +68,24 @@ SUITE(bounds_test)
TEST (bounds_convertible) TEST (bounds_convertible)
{ {
static_bounds<size_t, 7, 4, 2> b1; static_bounds<7, 4, 2> b1;
static_bounds<size_t, 7, dynamic_range, 2> b2 = b1; static_bounds<7, dynamic_range, 2> b2 = b1;
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
static_bounds<size_t, 7, dynamic_range, 1> b4 = b2; static_bounds<7, dynamic_range, 1> b4 = b2;
#endif #endif
static_bounds<size_t, dynamic_range, dynamic_range, dynamic_range> b3 = b1; static_bounds<dynamic_range, dynamic_range, dynamic_range> b3 = b1;
static_bounds<int, 7, 4, 2> b4 = b3; static_bounds<7, 4, 2> b4 = b3;
static_bounds<size_t, dynamic_range> b11; static_bounds<dynamic_range> b11;
static_bounds<size_t, dynamic_range> b5; static_bounds<dynamic_range> b5;
static_bounds<size_t, 34> b6; static_bounds<34> b6;
b5 = static_bounds<size_t, 20>(); b5 = static_bounds<20>();
CHECK_THROW(b6 = b5, fail_fast); CHECK_THROW(b6 = b5, fail_fast);
b5 = static_bounds<size_t, 34>(); b5 = static_bounds<34>();
b6 = b5; b6 = b5;
CHECK(b5 == b6); CHECK(b5 == b6);

View File

@ -1,304 +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>
#include <vector>
#include <iostream>
using namespace gsl;
struct MyBase { bool foo() { return true; } };
struct MyDerived : public MyBase {};
struct Unrelated {};
SUITE(MaybeNullTests)
{
TEST(TestMaybeNull1)
{
#ifdef CONFIRM_COMPILATION_ERRORS
// Forbid non-nullptr assignable types
maybe_null_ret<std::vector<int>> f_ret(std::vector<int>{1});
maybe_null_ret<std::vector<int>> f_ret(std::vector<int>{1});
maybe_null_ret<int> z_ret(10);
maybe_null_dbg<std::vector<int>> y_dbg({1,2});
maybe_null_dbg<int> z_dbg(10);
maybe_null_dbg<std::vector<int>> y_dbg({1,2});
#endif
int n = 5;
maybe_null_dbg<int *> opt_n(&n);
int result = 0;
bool threw = false;
CHECK_THROW(result = *opt_n, fail_fast);
maybe_null_ret<std::shared_ptr<int>> x_ret(std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
maybe_null_dbg<std::shared_ptr<int>> x_dbg(std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
}
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);
maybe_null_dbg<MyDerived*> pdbg = &derived;
CHECK(pdbg.present());
maybe_null_dbg<MyBase*> qdbg = pdbg;
CHECK(qdbg == pdbg);
#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());
}
TEST(TestMaybeNullCompare)
{
int i1 = 1;
int i2 = 2;
maybe_null_dbg<int*> p1 = &i1;
maybe_null_dbg<int*> p1_2 = &i1;
maybe_null_dbg<int*> p2 = &i2;
CHECK_THROW(p1.get(), fail_fast);
CHECK_THROW(p1_2.get(), fail_fast);
CHECK_THROW(p2.get(), fail_fast);
CHECK(p1 != p2);
CHECK(!(p1 == p2));
CHECK(p1 == p1);
CHECK(p1 == p1_2);
// Make sure we no longer throw here
CHECK(p1.get() != nullptr);
CHECK(p1_2.get() != nullptr);
CHECK(p2.get() != nullptr);
}
TEST(TestMaybeNullCopy)
{
int i1 = 1;
int i2 = 2;
maybe_null_dbg<int*> p1 = &i1;
maybe_null_dbg<int*> p1_2 = &i1;
maybe_null_dbg<int*> p2 = &i2;
CHECK(p1 != p2);
CHECK(p1 == p1_2);
// Make sure we no longer throw here
CHECK(p1.get() != nullptr);
CHECK(p2.get() != nullptr);
p1 = p2;
// Make sure we now throw
CHECK_THROW(p1.get(), fail_fast);
CHECK(p1 == p2);
CHECK(p1 != p1_2);
// Make sure we no longer throw here
CHECK(p1.get() != nullptr);
}
TEST(TestMaybeNullAssignmentOps)
{
MyBase base;
MyDerived derived;
Unrelated unrelated;
not_null<MyBase*> nnBase(&base);
not_null<MyDerived*> nnDerived(&derived);
not_null<Unrelated*> nnUnrelated(&unrelated);
maybe_null_ret<MyBase*> mnBase_ret1(&base), mnBase_ret2;
mnBase_ret2 = mnBase_ret1; // maybe_null_ret<T> = maybe_null_ret<T>
mnBase_ret2 = nnBase; // maybe_null_ret<T> = not_null<T>
maybe_null_ret<MyDerived*> mnDerived_ret(&derived);
mnBase_ret2 = mnDerived_ret; // maybe_null_ret<T> = maybe_null_ret<U>
mnBase_ret1 = &derived; // maybe_null_ret<T> = U;
mnBase_ret1 = nnDerived; // maybe_null_ret<T> = not_null<U>
maybe_null_ret<Unrelated*> mnUnrelated_ret;
mnUnrelated_ret = &unrelated; // maybe_null_ret<T> = T
maybe_null_dbg<MyBase*> mnBase_dbg1(&base), mnBase_dbg2;
mnBase_dbg2 = mnBase_dbg1; // maybe_null_dbg<T> = maybe_null_dbg<T>
mnBase_dbg2 = nnBase; // maybe_null_dbg<T> = not_null<T>
maybe_null_dbg<MyDerived*> mnDerived_dbg(&derived);
mnBase_dbg2 = mnDerived_dbg; // maybe_null_dbg<T> = maybe_null_dbg<U>
mnBase_dbg1 = &derived; // maybe_null_dbg<T> = U;
mnBase_dbg1 = nnDerived; // maybe_null_dbg<T> = not_null<U>
maybe_null_dbg<Unrelated*> mnUnrelated_dbg;
mnUnrelated_dbg = &unrelated; // maybe_null_dbg<T> = T
}
}
int main(int, const char *[])
{
return UnitTest::RunAllTests();
}

File diff suppressed because it is too large Load Diff

View File

@ -15,38 +15,39 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <UnitTest++/UnitTest++.h> #include <UnitTest++/UnitTest++.h>
#include <string_view.h> #include <string_span.h>
#include <vector> #include <vector>
#include <cstdlib> #include <cstdlib>
using namespace std; using namespace std;
using namespace gsl; using namespace gsl;
SUITE(string_view_tests)
SUITE(string_span_tests)
{ {
TEST(TestLiteralConstruction) TEST(TestLiteralConstruction)
{ {
cwstring_view<> v = ensure_z(L"Hello"); cwstring_span<> v = ensure_z(L"Hello");
CHECK(5 == v.length()); CHECK(5 == v.length());
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
wstring_view<> v2 = ensure0(L"Hello"); wstring_span<> v2 = ensure0(L"Hello");
#endif #endif
} }
TEST(TestConstructFromStdString) TEST(TestConstructFromStdString)
{ {
std::string s = "Hello there world"; std::string s = "Hello there world";
cstring_view<> v = s; cstring_span<> v = s;
CHECK(v.length() == s.length()); CHECK(v.length() == s.length());
} }
TEST(TestConstructFromStdVector) TEST(TestConstructFromStdVector)
{ {
std::vector<char> vec('h', 5); std::vector<char> vec(5, 'h');
string_view<> v = vec; string_span<> v = vec;
CHECK(v.length() == vec.size()); CHECK(v.length() == vec.size());
} }
@ -55,47 +56,67 @@ SUITE(string_view_tests)
wchar_t stack_string[] = L"Hello"; wchar_t stack_string[] = L"Hello";
{ {
cwstring_view<> v = ensure_z(stack_string); cwstring_span<> v = ensure_z(stack_string);
CHECK(v.length() == 5); CHECK(v.length() == 5);
CHECK(v.used_length() == v.length()); CHECK(v.used_length() == v.length());
} }
{ {
cwstring_view<> v = stack_string; cwstring_span<> v = stack_string;
CHECK(v.length() == 6); CHECK(v.length() == 6);
CHECK(v.used_length() == v.length()); CHECK(v.used_length() == v.length());
} }
{ {
wstring_view<> v = ensure_z(stack_string); wstring_span<> v = ensure_z(stack_string);
CHECK(v.length() == 5); CHECK(v.length() == 5);
CHECK(v.used_length() == v.length()); CHECK(v.used_length() == v.length());
} }
{ {
wstring_view<> v = stack_string; wstring_span<> v = stack_string;
CHECK(v.length() == 6); CHECK(v.length() == 6);
CHECK(v.used_length() == v.length()); CHECK(v.used_length() == v.length());
} }
} }
TEST(TestConstructFromConstCharPointer)
{
const char* s = "Hello";
cstring_span<> 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";
string_view<> v = ensure_z(stack_string); string_span<> v = ensure_z(stack_string);
cstring_view<> v2 = v; cstring_span<> v2 = v;
CHECK(v.length() == v2.length()); CHECK(v.length() == v2.length());
} }
TEST(TestConversionFromConst) TEST(TestConversionFromConst)
{ {
char stack_string[] = "Hello"; char stack_string[] = "Hello";
cstring_view<> v = ensure_z(stack_string); cstring_span<> v = ensure_z(stack_string);
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
string_view<> v2 = v; string_span<> v2 = v;
string_view<> v3 = "Hello"; string_span<> v3 = "Hello";
#endif #endif
} }
TEST(TestToString)
{
auto s = gsl::to_string(cstring_span<>{});
CHECK(s.length() == 0);
char stack_string[] = "Hello";
cstring_span<> v = ensure_z(stack_string);
auto s2 = gsl::to_string(v);
CHECK(s2.length() == v.length());
CHECK(s2.length() == 5);
}
} }
int main(int, const char *[]) int main(int, const char *[])

View File

@ -47,6 +47,11 @@ SUITE(utils_tests)
CHECK(i == 0); CHECK(i == 0);
} }
CHECK(i == 1); CHECK(i == 1);
{
auto _2 = std::move(_1);
CHECK(i == 1);
}
CHECK(i == 1);
} }
CHECK(i == 1); CHECK(i == 1);
} }