Merge remote-tracking branch 'upstream/master' into kernhanda/use_typetraits

This commit is contained in:
Kern Handa 2015-09-30 18:54:09 +00:00
commit 9f93179086
15 changed files with 371 additions and 244 deletions

View File

@ -26,6 +26,7 @@ The test suite that exercises GSL has been built and passes successfully on the
* GNU/Linux using GCC 5.1
* OS X Yosemite using Xcode with AppleClang 7.0.0.7000072
* OS X Yosemite using GCC-5.2.0
* FreeBSD 10.x with Clang/LLVM 3.6
> If you successfully port GSL to another platform, we would love to hear from you. Please submit an issue to let us know. Also please consider
contributing any changes that were necessary back to this project to benefit the wider community.

File diff suppressed because it is too large Load Diff

View File

@ -22,14 +22,14 @@
#include <exception>
#include <stdexcept>
namespace Guide
namespace gsl
{
//
// Having "fail fast" result in an exception makes unit testing
// the GSL classes that rely upon it much simpler.
//
#if defined(SAFER_CPP_TESTING)
#if defined(GSL_THROWS_FOR_TESTING)
struct fail_fast : public std::runtime_error
{
@ -45,7 +45,7 @@ inline void fail_fast_assert(bool cond, const char* const message) { if (!cond)
inline void fail_fast_assert(bool cond) { if (!cond) std::terminate(); }
inline void fail_fast_assert(bool cond, const char* const) { if (!cond) std::terminate(); }
#endif // SAFER_CPP_TESTING
#endif // GSL_THROWS_FOR_TESTING
}

View File

@ -23,7 +23,7 @@
#include "string_view.h" // zstring, string_view, zstring_builder...
#include <memory>
namespace Guide
namespace gsl
{
//
@ -38,8 +38,8 @@ using owner = T;
//
// GSL.assert: assertions
//
#define Expects(x) Guide::fail_fast_assert((x))
#define Ensures(x) Guide::fail_fast_assert((x))
#define Expects(x) gsl::fail_fast_assert((x))
#define Ensures(x) gsl::fail_fast_assert((x))
//
// GSL.util: utilities
@ -50,16 +50,17 @@ template <class F>
class Final_act
{
public:
explicit Final_act(F f) : f_(std::move(f)) {}
explicit Final_act(F f) : f_(std::move(f)), invoke_(true) {}
Final_act(const Final_act&& other) : f_(other.f_) {}
Final_act(Final_act&& other) : f_(std::move(other.f_)), invoke_(true) { other.invoke_ = false; }
Final_act(const Final_act&) = delete;
Final_act& operator=(const Final_act&) = delete;
~Final_act() { f_(); }
~Final_act() { if (invoke_) f_(); }
private:
F f_;
bool invoke_;
};
// finally() - convenience function to generate a Final_act
@ -111,21 +112,27 @@ class not_null
static_assert(std::is_assignable<T&, std::nullptr_t>::value, "T cannot be assigned nullptr.");
public:
not_null(T t) : ptr_(t) { ensure_invariant(); }
// deleting these two prevents compilation when initialized with a nullptr or literal 0
not_null(std::nullptr_t) = delete;
not_null(int) = delete;
not_null& operator=(const T& t) { ptr_ = t; ensure_invariant(); return *this; }
not_null(const not_null &other) = default;
not_null& operator=(const not_null &other) = default;
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
not_null(const not_null<U> &other) : ptr_(other.get())
not_null(const not_null<U> &other)
{
*this = other;
}
not_null<T>& operator=(const T& t) { ptr_ = t; ensure_invariant(); return *this; }
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
not_null& operator=(const not_null<U> &other)
{
ptr_ = other.get();
return *this;
}
// prevents compilation when someone attempts to assign a nullptr
not_null(std::nullptr_t) = delete;
not_null(int) = delete;
not_null<T>& operator=(std::nullptr_t) = delete;
not_null<T>& operator=(int) = delete;
@ -166,26 +173,21 @@ private:
//
// 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(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)
@ -196,6 +198,8 @@ public:
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)
@ -206,12 +210,51 @@ public:
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); }
bool operator==(const maybe_null_dbg& rhs) const { tested_ = true; rhs.tested_ = true; return ptr_ == rhs.ptr_; }
bool operator!=(const maybe_null_dbg& 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_);
@ -225,8 +268,6 @@ public:
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;
@ -249,27 +290,46 @@ 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& operator=(const T& p) { ptr_ = p; return *this; }
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;
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_; }
@ -289,12 +349,11 @@ private:
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
} // namespace gsl
#endif // GSL_GSL_H

View File

@ -22,7 +22,7 @@
#include "array_view.h"
#include <cstring>
namespace Guide
namespace gsl
{
//
// czstring and wzstring
@ -137,7 +137,7 @@ basic_string_view<typename std::remove_pointer_t<typename Cont::pointer>, dynami
// to_string() allow (explicit) conversions from string_view to string
//
template<class CharT, size_t Extent>
std::basic_string<typename std::remove_const_t<CharT>> to_string(const basic_string_view<CharT, Extent>& view)
std::basic_string<std::remove_const_t<CharT>> to_string(basic_string_view<CharT, Extent> view)
{
return{ view.data(), view.length() };
}
@ -164,7 +164,7 @@ public:
size_type length() const { return sv_.length(); }
pointer assume0() const { return data(); }
string_view_type ensure_z() const { return Guide::ensure_z(sv_); }
string_view_type ensure_z() const { return gsl::ensure_z(sv_); }
iterator begin() const { return sv_.begin(); }
iterator end() const { return sv_.end(); }

View File

@ -9,7 +9,7 @@ include_directories(
./unittest-cpp
)
add_definitions(-DSAFER_CPP_TESTING)
add_definitions(-DGSL_THROWS_FOR_TESTING)
if(MSVC14 OR MSVC12) # has the support we need
# remove unnecessary warnings about unchecked iterators

View File

@ -27,7 +27,7 @@
using namespace std;
using namespace Guide;
using namespace gsl;
namespace
{
@ -261,8 +261,8 @@ SUITE(array_view_tests)
int a[30][4][5];
auto av = as_array_view(a);
auto sub = av.section({15, 0, 0}, Guide::index<3>{2, 2, 2});
auto subsub = sub.section({1, 0, 0}, Guide::index<3>{1, 1, 1});
auto sub = av.section({15, 0, 0}, gsl::index<3>{2, 2, 2});
auto subsub = sub.section({1, 0, 0}, gsl::index<3>{1, 1, 1});
}
TEST(array_view_section)

View File

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

View File

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

View File

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

View File

@ -17,8 +17,9 @@
#include <UnitTest++/UnitTest++.h>
#include <gsl.h>
#include <vector>
#include <iostream>
using namespace Guide;
using namespace gsl;
struct MyBase { bool foo() { return true; } };
struct MyDerived : public MyBase {};
@ -177,13 +178,19 @@ SUITE(MaybeNullTests)
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);
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());
@ -254,6 +261,41 @@ SUITE(MaybeNullTests)
// 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 *[])

View File

@ -18,7 +18,7 @@
#include <gsl.h>
#include <vector>
using namespace Guide;
using namespace gsl;
struct MyBase {};
struct MyDerived : public MyBase {};
@ -65,12 +65,19 @@ SUITE(NotNullTests)
TEST(TestNotNullCasting)
{
MyDerived derived;
MyBase base;
MyDerived derived;
Unrelated unrelated;
not_null<Unrelated*> u = &unrelated;
not_null<MyDerived*> p = &derived;
not_null<MyBase*> q = p;
not_null<MyBase*> q = &base;
q = p; // allowed with heterogeneous copy ctor
CHECK(q == p);
#ifdef CONFIRM_COMPILATION_ERRORS
q = u; // no viable conversion possible between MyBase* and Unrelated*
p = q; // not possible to implicitly convert MyBase* to MyDerived*
not_null<Unrelated*> r = p;
not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
#endif

View File

@ -18,7 +18,7 @@
#include <gsl.h>
#include <functional>
using namespace Guide;
using namespace gsl;
SUITE(owner_tests)
{

View File

@ -20,7 +20,7 @@
#include <cstdlib>
using namespace std;
using namespace Guide;
using namespace gsl;
SUITE(string_view_tests)
{

View File

@ -18,7 +18,7 @@
#include <gsl.h>
#include <functional>
using namespace Guide;
using namespace gsl;
SUITE(utils_tests)
{
@ -37,6 +37,20 @@ SUITE(utils_tests)
CHECK(i == 1);
}
TEST(finally_lambda_move)
{
int i = 0;
{
auto _1 = finally([&]() {f(i);});
{
auto _2 = std::move(_1);
CHECK(i == 0);
}
CHECK(i == 1);
}
CHECK(i == 1);
}
TEST(finally_function_with_bind)
{
int i = 0;