mirror of
https://github.com/microsoft/GSL.git
synced 2025-02-22 09:22:52 -05:00
Merge remote-tracking branch 'refs/remotes/Microsoft/master'
This commit is contained in:
commit
2b2adebde5
@ -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
13
.gitignore
vendored
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
# GSL: Guidelines Support Library [](https://travis-ci.org/Microsoft/GSL)
|
# GSL: Guidelines Support Library [](https://travis-ci.org/Microsoft/GSL) [](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
|
||||||
|
2305
include/array_view.h
2305
include/array_view.h
File diff suppressed because it is too large
Load Diff
206
include/gsl.h
206
include/gsl.h
@ -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
1988
include/span.h
Normal file
File diff suppressed because it is too large
Load Diff
227
include/string_span.h
Normal file
227
include/string_span.h
Normal 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
|
@ -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
|
|
@ -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)
|
||||||
|
@ -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,20 +42,20 @@ 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();
|
||||||
|
|
||||||
@ -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);
|
||||||
|
@ -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
@ -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 *[])
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user