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 * GNU/Linux using GCC 5.1
* OS X Yosemite using Xcode with AppleClang 7.0.0.7000072 * OS X Yosemite using Xcode with AppleClang 7.0.0.7000072
* OS X Yosemite using GCC-5.2.0 * OS X Yosemite using GCC-5.2.0
* FreeBSD 10.x with Clang/LLVM 3.6
> If you successfully port GSL to another platform, we would love to hear from you. Please submit an issue to let us know. Also please consider > If you successfully port GSL to another platform, we would love to hear from you. Please submit an issue to let us know. Also please consider
contributing any changes that were necessary back to this project to benefit the wider community. contributing any changes that were necessary back to this project to benefit the wider community.

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -23,7 +23,7 @@
#include "string_view.h" // zstring, string_view, zstring_builder... #include "string_view.h" // zstring, string_view, zstring_builder...
#include <memory> #include <memory>
namespace Guide namespace gsl
{ {
// //
@ -38,8 +38,8 @@ using owner = T;
// //
// GSL.assert: assertions // GSL.assert: assertions
// //
#define Expects(x) Guide::fail_fast_assert((x)) #define Expects(x) gsl::fail_fast_assert((x))
#define Ensures(x) Guide::fail_fast_assert((x)) #define Ensures(x) gsl::fail_fast_assert((x))
// //
// GSL.util: utilities // GSL.util: utilities
@ -50,16 +50,17 @@ template <class F>
class Final_act class Final_act
{ {
public: 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(const Final_act&) = delete;
Final_act& operator=(const Final_act&) = delete; Final_act& operator=(const Final_act&) = delete;
~Final_act() { f_(); } ~Final_act() { if (invoke_) f_(); }
private: private:
F f_; F f_;
bool invoke_;
}; };
// finally() - convenience function to generate a Final_act // finally() - convenience function to generate a Final_act
@ -111,21 +112,27 @@ class not_null
static_assert(std::is_assignable<T&, std::nullptr_t>::value, "T cannot be assigned nullptr."); static_assert(std::is_assignable<T&, std::nullptr_t>::value, "T cannot be assigned nullptr.");
public: public:
not_null(T t) : ptr_(t) { ensure_invariant(); } not_null(T t) : ptr_(t) { ensure_invariant(); }
not_null& operator=(const T& t) { ptr_ = t; ensure_invariant(); return *this; }
// deleting these two prevents compilation when initialized with a nullptr or literal 0
not_null(std::nullptr_t) = delete;
not_null(int) = delete;
not_null(const not_null &other) = default; not_null(const not_null &other) = default;
not_null& operator=(const not_null &other) = default;
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>> template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
not_null(const not_null<U> &other) : ptr_(other.get()) not_null(const not_null<U> &other)
{ {
*this = other;
} }
not_null<T>& operator=(const T& t) { ptr_ = t; ensure_invariant(); return *this; } template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
not_null& operator=(const not_null<U> &other)
{
ptr_ = other.get();
return *this;
}
// prevents compilation when someone attempts to assign a nullptr // prevents compilation when someone attempts to assign a nullptr
not_null(std::nullptr_t) = delete;
not_null(int) = delete;
not_null<T>& operator=(std::nullptr_t) = delete; not_null<T>& operator=(std::nullptr_t) = delete;
not_null<T>& operator=(int) = delete; not_null<T>& operator=(int) = delete;
@ -166,26 +173,21 @@ private:
// //
// Describes an optional pointer - provides symmetry with not_null // Describes an optional pointer - provides symmetry with not_null
// //
template<class T>
class maybe_null_ret;
template<class T> template<class T>
class maybe_null_dbg 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."); static_assert(std::is_assignable<T&, std::nullptr_t>::value, "T cannot be assigned nullptr.");
public: public:
maybe_null_dbg() : ptr_(nullptr), tested_(false) {} 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 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) maybe_null_dbg& operator=(const T& p)
{ {
if (ptr_ != p) if (ptr_ != p)
@ -196,6 +198,8 @@ public:
return *this; return *this;
} }
maybe_null_dbg(const maybe_null_dbg& rhs) : ptr_(rhs.ptr_), tested_(false) {}
maybe_null_dbg& operator=(const maybe_null_dbg& rhs) maybe_null_dbg& operator=(const maybe_null_dbg& rhs)
{ {
if (this != &rhs) if (this != &rhs)
@ -206,12 +210,51 @@ public:
return *this; 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 present() const { tested_ = true; return ptr_ != nullptr; }
bool operator==(const T& rhs) const { tested_ = true; return ptr_ == rhs; } bool operator==(const T& rhs) const { tested_ = true; return ptr_ == rhs; }
bool operator!=(const T& rhs) const { return !(*this == 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_; } template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
bool operator!=(const maybe_null_dbg& rhs) const { return !(*this == rhs); } 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 { T get() const {
fail_fast_assert(tested_); fail_fast_assert(tested_);
@ -225,8 +268,6 @@ public:
T operator->() const { return get(); } T operator->() const { return get(); }
private: private:
const size_t ptee_size_ = sizeof(*ptr_); // T must be a pointer type
// unwanted operators...pointers only point to single objects! // unwanted operators...pointers only point to single objects!
// TODO ensure all arithmetic ops on this type are unavailable // TODO ensure all arithmetic ops on this type are unavailable
maybe_null_dbg<T>& operator++() = delete; maybe_null_dbg<T>& operator++() = delete;
@ -249,27 +290,46 @@ class maybe_null_ret
public: public:
maybe_null_ret() : ptr_(nullptr) {} maybe_null_ret() : ptr_(nullptr) {}
maybe_null_ret(std::nullptr_t) : ptr_(nullptr) {} maybe_null_ret(std::nullptr_t) : ptr_(nullptr) {}
maybe_null_ret(const T& p) : ptr_(p) {} 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(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; 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; } bool present() const { return ptr_ != nullptr; }
T get() const { return ptr_; } 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;
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_; T ptr_;
}; };
template<class T> using maybe_null = maybe_null_ret<T>; template<class T> using maybe_null = maybe_null_ret<T>;
} // namespace Guide } // namespace gsl
#endif // GSL_GSL_H #endif // GSL_GSL_H

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,8 +17,9 @@
#include <UnitTest++/UnitTest++.h> #include <UnitTest++/UnitTest++.h>
#include <gsl.h> #include <gsl.h>
#include <vector> #include <vector>
#include <iostream>
using namespace Guide; using namespace gsl;
struct MyBase { bool foo() { return true; } }; struct MyBase { bool foo() { return true; } };
struct MyDerived : public MyBase {}; struct MyDerived : public MyBase {};
@ -177,6 +178,12 @@ SUITE(MaybeNullTests)
maybe_null<MyBase*> q = p; maybe_null<MyBase*> q = p;
CHECK(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 #ifdef CONFIRM_COMPILATION_ERRORS
maybe_null<Unrelated*> r = p; maybe_null<Unrelated*> r = p;
maybe_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p); maybe_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
@ -254,6 +261,41 @@ SUITE(MaybeNullTests)
// Make sure we no longer throw here // Make sure we no longer throw here
CHECK(p1.get() != nullptr); 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 *[]) int main(int, const char *[])

View File

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

View File

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

View File

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

View File

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