Преглед на файлове

Compressing noexcept messages with aliases in a detail namespace

Samuel Jaffe преди 8 години
родител
ревизия
230403ed05
променени са 7 файла, в които са добавени 78 реда и са изтрити 67 реда
  1. 8 8
      const_propogating_ptr.hpp
  2. 3 3
      const_ptr.hpp
  3. 27 31
      maybe_null.hpp
  4. 3 2
      maybe_null.t.h
  5. 15 21
      not_null.hpp
  6. 21 1
      pointer_fwd.hpp
  7. 1 1
      value_ptr.hpp

+ 8 - 8
const_propogating_ptr.hpp

@@ -21,23 +21,23 @@ public:
   using const_reference = element_type const &;
 
   const_propogating_ptr() noexcept : _ptr(nullptr) {}
-  const_propogating_ptr(P const & p) noexcept(std::is_nothrow_copy_constructible<P>::value) : _ptr(p) {}
-  const_propogating_ptr(P && p) noexcept(std::is_nothrow_move_constructible<P>::value) : _ptr(std::move(p)) {}
+  const_propogating_ptr(P const & p) noexcept(detail::is_nt_cc<P>::value) : _ptr(p) {}
+  const_propogating_ptr(P && p) noexcept(detail::is_nt_mc<P>::value) : _ptr(std::move(p)) {}
   
-  const_propogating_ptr(const_propogating_ptr &) noexcept(std::is_nothrow_copy_constructible<P>::value) = default;
-  const_propogating_ptr(const_propogating_ptr &&) noexcept(std::is_nothrow_move_constructible<P>::value) = default;
+  const_propogating_ptr(const_propogating_ptr &) noexcept(detail::is_nt_cc<P>::value) = default;
+  const_propogating_ptr(const_propogating_ptr &&) noexcept(detail::is_nt_mc<P>::value) = default;
   const_propogating_ptr(const_propogating_ptr const &) = delete;
-  const_propogating_ptr& operator=(const_propogating_ptr &) noexcept(std::is_nothrow_copy_constructible<P>::value) = default;
-  const_propogating_ptr& operator=(const_propogating_ptr &&) noexcept(std::is_nothrow_move_constructible<P>::value) = default;
+  const_propogating_ptr& operator=(const_propogating_ptr &) noexcept(detail::is_nt_ca<P>::value) = default;
+  const_propogating_ptr& operator=(const_propogating_ptr &&) noexcept(detail::is_nt_ma<P>::value) = default;
   const_propogating_ptr& operator=(const_propogating_ptr const &) = delete;
   
   template <typename Y>
-  explicit operator const_propogating_ptr<Y>() & noexcept(std::is_nothrow_copy_constructible<Y>::value) {
+  explicit operator const_propogating_ptr<Y>() & noexcept(detail::is_nt_c<P, Y>::value) {
     return _ptr;
   }
   
   template <typename Y>
-  explicit operator const_ptr<Y>() const noexcept(std::is_nothrow_copy_constructible<Y>::value) {
+  explicit operator const_ptr<Y>() const noexcept(detail::is_nt_c<P, Y>::value) {
     return _ptr;
   }
   

+ 3 - 3
const_ptr.hpp

@@ -19,11 +19,11 @@ public:
   using reference = element_type const &;
 
   const_ptr() noexcept : _ptr(nullptr) {}
-  const_ptr(P const & p) noexcept(std::is_nothrow_copy_constructible<P>::value) : _ptr(p) {}
-  const_ptr(P && p) noexcept(std::is_nothrow_move_constructible<P>::value) : _ptr(std::move(p)) {}
+  const_ptr(P const & p) noexcept(detail::is_nt_cc<P>::value) : _ptr(p) {}
+  const_ptr(P && p) noexcept(detail::is_nt_mc<P>::value) : _ptr(std::move(p)) {}
   
   template <typename Y>
-  explicit operator const_ptr<Y>() const noexcept(std::is_nothrow_copy_constructible<Y>::value) {
+  explicit operator const_ptr<Y>() const noexcept(detail::is_nt_c<P, Y>::value) {
     return _ptr;
   }
   

+ 27 - 31
maybe_null.hpp

@@ -8,7 +8,6 @@
 
 #pragma once
 
-#include <stdexcept>
 #include <memory>
 
 #include "pointer_fwd.hpp"
@@ -20,38 +19,33 @@ class unchecked_pointer_exception : public std::logic_error {
 
 template <typename P> class maybe_null<not_null<P>>; // not permitted
 
-template <typename T>
+#if defined( DEBUG )
+#define set_tested( value ) tested_ = value
+#else
+#define set_tested( _ )
+#endif
+
+template <typename P>
 class maybe_null {
 public:
-  using element_type = typename std::pointer_traits<T>::element_type;
+  using element_type = typename std::pointer_traits<P>::element_type;
   using pointer = element_type *;
   using reference = element_type &;
   
   maybe_null() noexcept : _ptr(nullptr) {}
-  maybe_null(T const & p) noexcept(std::is_nothrow_copy_constructible<T>::value) : _ptr(p) { }
-  maybe_null(T && p) noexcept(std::is_nothrow_move_constructible<T>::value) : _ptr(std::move(p)) { }
-  maybe_null(maybe_null const&) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
-  
+  maybe_null(P const & p) noexcept(detail::is_nt_cc<P>::value) : _ptr(p) { }
+  maybe_null(P && p) noexcept(detail::is_nt_mc<P>::value) : _ptr(std::move(p)) { }
+  maybe_null(maybe_null const&) noexcept(detail::is_nt_cc<P>::value) = default;
+  maybe_null(maybe_null &&) noexcept(detail::is_nt_mc<P>::value) = default;
   template <typename Y>
-  explicit operator maybe_null<Y>() const noexcept(std::is_nothrow_copy_constructible<Y>::value) {
-    return _ptr;
-  }
+  maybe_null(maybe_null<Y> const&other) noexcept(detail::is_nt_c<P, Y>::value)
+  : _ptr(other._ptr) { set_tested(other.tested_); }
   
-  maybe_null& operator=(maybe_null const&) noexcept = default;
-  template <typename Y> maybe_null& operator=(maybe_null<Y> const&other) noexcept {
-    if (_ptr != other._ptr) {
-      _ptr = other._ptr;
-#if defined( DEBUG )
-      tested_ = other.tested_;
-#endif
-    }
-    return *this;
-  }
+  maybe_null& operator=(maybe_null const&) noexcept(detail::is_nt_ca<P>::value) = default;
+  maybe_null& operator=(maybe_null &&) noexcept(detail::is_nt_ma<P>::value) = default;
   
   operator bool() const noexcept {
-#if defined( DEBUG )
-    tested_ = true;
-#endif
+    set_tested(true);
     return static_cast<bool>(_ptr);
   }
   
@@ -59,21 +53,23 @@ public:
   pointer operator->() const /*throw(unchecked_pointer_exception)*/ {
     return std::addressof(operator*());
   }
-#if defined( DEBUG )
   reference operator*() const /*throw(unchecked_pointer_exception)*/ {
-    if ( !tested_ ) { throw unchecked_pointer_exception{"did not verify that pointer was non-null"}; }
-    return *_ptr;
-  }
-#else
-  reference operator*() const noexcept {
+#if defined( DEBUG )
+    if ( ! tested_ ) { throw unchecked_pointer_exception{"did not verify that pointer was non-null"}; }
+#endif
+    if ( ! _ptr ) { throw null_pointer_exception{"dereferencing maybe_null in null state"}; }
     return *_ptr;
   }
-#endif
+  
+  void reset( P const & p ) { operator=(maybe_null(p)); }
+  void reset( P && p = P() ) { operator=(maybe_null(std::forward(p))); }
 private:
-  T _ptr;
+  template <typename Y> friend class maybe_null;
+  P _ptr;
 #if defined( DEBUG )
   mutable bool tested_ = false;
 #endif
 };
 
+#undef set_tested
 POINTER_TEMPLATE_COMPARE( maybe_null )

+ 3 - 2
maybe_null.t.h

@@ -10,8 +10,9 @@
 #include <cxxtest/TestSuite.h>
 #include <memory>
 
-#undef DEBUG
+#ifndef DEBUG
 #define DEBUG
+#endif
 #include "maybe_null.hpp"
 
 class maybe_null_TestSuite : public CxxTest::TestSuite {
@@ -73,7 +74,7 @@ public:
     struct derived : public base {};
     derived d;
     maybe_null<derived*> m{&d};
-    maybe_null<base*> b = maybe_null<base*>(m);
+    maybe_null<base*> b = m;
     TS_ASSERT_EQUALS(b.get(), m.get());
   }
   

+ 15 - 21
not_null.hpp

@@ -8,61 +8,55 @@
 
 #pragma once
 
-#include <stdexcept>
 #include <memory>
 
 #include "pointer_fwd.hpp"
 #include "ptr_compare.hpp"
 #include "maybe_null.hpp"
 
-class null_pointer_exception : public std::invalid_argument {
-  using std::invalid_argument::invalid_argument;
-};
-
 template <typename P> class not_null<std::weak_ptr<P>>; // A weak_ptr cannot be a not_null
 
-template <typename T>
+template <typename P>
 class not_null {
 public:
-  using element_type = typename std::pointer_traits<T>::element_type;
+  using element_type = typename std::pointer_traits<P>::element_type;
   using pointer = element_type *;
   using reference = element_type &;
   
   explicit not_null(std::nullptr_t) = delete;
   explicit not_null(int) = delete;
-  not_null(T const & p) : _ptr(p) { validate(); }
-  not_null(T && p) : _ptr(std::move(p)) { validate(); }
-  not_null(not_null const&) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
-
+  not_null(P const & p) : _ptr(p) { validate(); }
+  not_null(P && p) : _ptr(std::move(p)) { validate(); }
+  not_null(not_null const&) noexcept(detail::is_nt_cc<P>::value) = default;
+  not_null(not_null &&) = delete;
+  
   template <typename Y>
-  explicit operator maybe_null<Y>() const noexcept(std::is_nothrow_constructible<Y, T>::value) {
+  explicit operator maybe_null<Y>() const noexcept(detail::is_nt_c<Y, P>::value) {
     return _ptr;
   }
   template <typename Y>
-  explicit operator not_null<Y>() const noexcept(std::is_nothrow_constructible<Y, T>::value) {
+  explicit operator not_null<Y>() const noexcept(detail::is_nt_c<Y, P>::value) {
     return _ptr;
   }
 
-  not_null& operator=(not_null const&) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
-  template <typename Y> not_null& operator=(not_null<Y> const&other) noexcept(std::is_nothrow_copy_constructible<T>::value) {
-    _ptr = other._ptr;
-    return *this;
-  }
+  not_null& operator=(not_null const&) noexcept(detail::is_nt_ca<P>::value) = default;
+  not_null& operator=(not_null &&) = delete;
   
-  explicit operator maybe_null<T>() const noexcept(std::is_nothrow_copy_constructible<T>::value);
   operator bool() const noexcept { return true; }
   
   pointer get() const noexcept { return std::addressof(operator*()); }
   reference operator*() const noexcept { return *_ptr; }
   pointer operator->() const noexcept { return get(); }
   
+  void reset( P const & p ) { operator=(not_null(p)); }
+  void reset( P && p ) { operator=(not_null(std::forward(p))); }
 private:
   void validate() {
     if (get() == nullptr) {
-      throw null_pointer_exception{"not_null<T> cannot be null"};
+      throw null_pointer_exception{"not_null<P> cannot be null"};
     }
   }
-  T _ptr;
+  P _ptr;
 };
 
 POINTER_TEMPLATE_COMPARE( not_null )

+ 21 - 1
pointer_fwd.hpp

@@ -7,6 +7,8 @@
 
 #pragma once
 
+#include <stdexcept>
+
 template <typename> class not_null;
 template <typename> class maybe_null;
 template <typename> class owner;
@@ -14,4 +16,22 @@ template <typename> class const_propogating_ptr;
 template <typename> class const_ptr;
 
 class unchecked_pointer_exception;
-class null_pointer_exception;
+
+class null_pointer_exception : public std::invalid_argument {
+  using std::invalid_argument::invalid_argument;
+};
+
+namespace detail {
+  template <typename P>
+  using is_nt_cc = std::is_nothrow_copy_constructible<P>;
+  template <typename P>
+  using is_nt_ca = std::is_nothrow_copy_assignable<P>;
+  template <typename P>
+  using is_nt_mc = std::is_nothrow_move_constructible<P>;
+  template <typename P>
+  using is_nt_ma = std::is_nothrow_move_assignable<P>;
+  template <typename P, typename Y>
+  using is_nt_c = std::is_nothrow_constructible<P, Y>;
+  template <typename P, typename Y>
+  using is_nt_a = std::is_nothrow_assignable<P, Y>;
+}

+ 1 - 1
value_ptr.hpp

@@ -46,7 +46,7 @@ public:
   
   value_ptr() noexcept : _ptr(nullptr) {}
   value_ptr(T * const & p) = delete;
-  value_ptr(T * && p) noexcept(std::is_nothrow_move_constructible<T>::value) : _ptr(std::move(p)) {}
+  value_ptr(T * && p) noexcept(detail::is_nt_mc<T>::value) : _ptr(std::move(p)) {}
   value_ptr(value_ptr const & other) : _ptr(detail::value_ptr_copy<T>::Copy(other._ptr)) {}
   value_ptr(value_ptr && other) noexcept(noexcept(std::swap(_ptr, other._ptr))) : _ptr(nullptr) { std::swap(_ptr, other._ptr); }
   static value_ptr copy_of(T * const & p) {