Scope
 All Classes Functions Pages
scope.hpp
1 /****************************************************************************
2  * \file scope.hpp
3  *
4  * This header contains the definition for scope utilities, as defined in the
5  * p0052r6 proposal paper:
6  * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0052r6.pdf
7  *
8  * This file is written in C++11, with compatible extensions for C++17
9  * through the constructor deduction guides.
10  ****************************************************************************/
11 
12 // Copyright Matthew Rodusek 2019.
13 // Distributed under the Boost Software License, Version 1.0.
14 // (See accompanying file LICENSE or copy at
15 // https://www.boost.org/LICENSE_1_0.txt)
16 #ifndef SCOPE_SCOPE_HPP
17 #define SCOPE_SCOPE_HPP
18 
19 #include <type_traits> // std::decay, std::is_*
20 #include <functional> // std::reference_wrapper, std::ref
21 #include <utility> // std::forward, std::move
22 #include <exception> // std::uncaught_exception(s)
23 #include <limits> // std::numeric_limits
24 
33 #if __cplusplus >= 201703L
34 # define SCOPE_NODISCARD [[nodiscard]]
35 #elif defined(__GNUC__) || defined(__CLANG__)
36 # define SCOPE_NODISCARD __attribute__ ((warn_unused_result))
37 #elif defined(_MSC_VER) && (_MSC_VER >= 1700)
38 # define SCOPE_NODISCARD _Check_return_
39 #else
40 # define SCOPE_NODISCARD
41 #endif
42 
43 // The large #if/endif block below, and the definition of
44 // scope::detail::uncaught_exception_count is adapted from boost:
45 // https://beta.boost.org/doc/libs/develop/boost/core/uncaught_exceptions.hpp
46 
47 // Copyright Andrey Semashev 2018.
48 // Distributed under the Boost Software License, Version 1.0.
49 // (See accompanying file LICENSE_1_0.txt or copy at
50 // http://www.boost.org/LICENSE_1_0.txt)
51 
52 #if (defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411) || \
53  defined(_MSC_VER) && _MSC_VER >= 1900
54 # define SCOPE_HAS_UNCAUGHT_EXCEPTIONS
55 #endif
56 
57 #if !defined(SCOPE_HAS_UNCAUGHT_EXCEPTIONS)
58 
59 // cxxabi.h availability macro
60 # if defined(__has_include)
61 # if __has_include(<cxxabi.h>)
62 # define SCOPE_HAS_CXXABI_H
63 # endif
64 # elif defined(__GLIBCXX__) || defined(__GLIBCPP__)
65 # define SCOPE_HAS_CXXABI_H
66 # endif
67 
68 # if defined(SCOPE_HAS_CXXABI_H)
69 // MinGW GCC 4.4 seem to not work the same way the newer GCC versions do. As
70 // a result, __cxa_get_globals based implementation will always return 0.
71 // Just disable it for now and fall back to std::uncaught_exception().
72 # if !(defined(__MINGW32__) && (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) < 405))
73 # include <cxxabi.h>
74 # include <cstring>
75 # define SCOPE_HAS_CXA_GET_GLOBALS
76 
77 // At least on MinGW and Linux, only GCC since 4.7 declares __cxa_get_globals()
78 // in cxxabi.h. Older versions of GCC do not expose this function but it's
79 // there.
80 // On OpenBSD, it seems, the declaration is also missing.
81 // Note that at least on FreeBSD 11, cxxabi.h declares __cxa_get_globals with
82 // a different exception specification, so we can't declare the function
83 // unconditionally. On Linux with clang and libc++ and on OS X, there is a
84 // version of cxxabi.h from libc++abi that doesn't declare __cxa_get_globals,
85 // but provides __cxa_uncaught_exceptions.
86 // The function only appeared in version _LIBCPPABI_VERSION >= 1002 of the
87 // library. Unfortunately, there are linking errors about undefined reference
88 // to __cxa_uncaught_exceptions on Ubuntu Trusty and OS X, so we avoid using
89 // it and forward-declare __cxa_get_globals instead. On QNX SDP 7.0 (QCC 5.4.0),
90 // there are multiple cxxabi.h, one from glibcxx from gcc and another from
91 // libc++abi from LLVM. Which one is included will be determined by the qcc
92 // command line arguments (-V and/or -Y;
93 // http://www.qnx.com/developers/docs/7.0.0/#com.qnx.doc.neutrino.utilities/topic/q/qcc.html
94 // ).
95 // The LLVM libc++abi is missing the declaration of __cxa_get_globals but it is
96 // also patched by QNX developers to not define _LIBCPPABI_VERSION. Older QNX
97 // SDP versions, up to and including 6.6, don't provide LLVM and libc++abi.
98 // See https://github.com/boostorg/core/issues/59.
99 # if !defined(__FreeBSD__) && \
100  ( \
101  (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) < 407) || \
102  defined(__OpenBSD__) || \
103  (defined(__QNXNTO__) && !defined(__GLIBCXX__) && !defined(__GLIBCPP__)) || \
104  defined(_LIBCPPABI_VERSION) \
105  )
106 namespace __cxxabiv1 {
107  struct __cxa_eh_globals;
108 # if defined(__OpenBSD__)
109  extern "C" __cxa_eh_globals* __cxa_get_globals();
110 # else
111  extern "C" __cxa_eh_globals* __cxa_get_globals() noexcept __attribute__((__const__));
112 # endif
113 } // namespace __cxxabiv1
114 # endif
115 # endif // !(defined(__MINGW32__) && (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) < 405))
116 # endif // defined(SCOPE_HAS_CXXABI_H)
117 
118 # if defined(_MSC_VER) && _MSC_VER >= 1400
119 # include <cstring>
120 # define SCOPE_HAS_GETPTD
121 namespace scope {
122  namespace detail {
123  extern "C" void* _getptd();
124  } // namespace detail
125 } // namespace scope
126 # endif // defined(_MSC_VER) && _MSC_VER >= 1400
127 #endif // !defined(SCOPE_HAS_UNCAUGHT_EXCEPTIONS)
128 
129 #if !defined(SCOPE_HAS_UNCAUGHT_EXCEPTIONS) && \
130  !defined(SCOPE_HAS_CXA_GET_GLOBALS) && \
131  !defined(SCOPE_HAS_GETPTD)
132 # define SCOPE_UNCAUGHT_EXCEPTIONS_EMULATED
135 #endif
136 
137 namespace scope {
138 
139  //==========================================================================
140  // implementation utilities
141  //==========================================================================
142 
143  namespace detail {
144 
145  inline int uncaught_exception_count()
146  {
147 #if defined(SCOPE_HAS_UNCAUGHT_EXCEPTIONS)
148  // C++17 implementation
149  return std::uncaught_exceptions();
150 #elif defined(SCOPE_HAS_CXA_GET_GLOBALS)
151  // Tested on {clang 3.2,GCC 3.5.6,GCC 4.1.2,GCC 4.4.6,GCC 4.4.7}x{x32,x64}
152  using byte = unsigned char;
153  auto count = int{};
154  const auto* ptr = reinterpret_cast<const byte*>(::abi::__cxa_get_globals()) + sizeof(void*);
155 
156  // __cxa_eh_globals::uncaughtExceptions, x32 offset - 0x4, x64 - 0x8
157  std::memcpy(&count, ptr, sizeof(count));
158  return count;
159 #elif defined(SCOPE_HAS_GETPTD)
160  // MSVC specific. Tested on {MSVC2005SP1,MSVC2008SP1,MSVC2010SP1,MSVC2012}x{x32,x64}.
161  using byte = unsigned char;
162  auto count = int{};
163 
164  const auto offset = (sizeof(void*) == 8u ? 0x100 : 0x90);
165  const auto* ptr = static_cast<const byte*>(::scope::detail::_getptd()) + offset;
166 
167  // _tiddata::_ProcessingThrow, x32 offset - 0x90, x64 - 0x100
168  std::memcpy(&count, ptr, sizeof(count));
169  return count;
170 #else
171  // Portable C++03 implementation. Does not allow to detect multiple
172  // nested exceptions.
173 
174  // This is a buggy fallback since it will only work with 1 exception
175  // in-flight, but we don't have any other options without exploiting
176  // internal compiler features.
177  return static_cast<int>(std::uncaught_exception());
178 #endif
179  }
180 
181  //========================================================================
182  // internal class : on_exit_policy
183  //========================================================================
184 
185  class on_exit_policy
186  {
187  public:
188  on_exit_policy() noexcept
189  : m_should_execute{true}
190  {
191 
192  }
193  on_exit_policy(on_exit_policy&&) = default;
194  on_exit_policy(const on_exit_policy&) = default;
195  on_exit_policy& operator=(on_exit_policy&&) = default;
196  on_exit_policy& operator=(const on_exit_policy&) = default;
197 
198  void release() noexcept
199  {
200  m_should_execute = false;
201  }
202 
203  bool should_execute() const noexcept
204  {
205  return m_should_execute;
206  }
207 
208  private:
209 
210  bool m_should_execute;
211  };
212 
213  //========================================================================
214  // internal class : on_fail_policy
215  //========================================================================
216 
217  class on_fail_policy
218  {
219  public:
220  on_fail_policy() noexcept
221  : m_exception_count{uncaught_exception_count()}
222  {
223 
224  }
225  on_fail_policy(on_fail_policy&&) = default;
226  on_fail_policy(const on_fail_policy&) = default;
227  on_fail_policy& operator=(on_fail_policy&&) = default;
228  on_fail_policy& operator=(const on_fail_policy&) = default;
229 
230  void release() noexcept
231  {
232  m_exception_count = std::numeric_limits<int>::max();
233  }
234 
235  bool should_execute() const noexcept
236  {
237  return m_exception_count < uncaught_exception_count();
238  }
239 
240  private:
241 
242  int m_exception_count;
243  };
244 
245  //========================================================================
246  // internal class : on_success_policy
247  //========================================================================
248 
249  class on_success_policy
250  {
251  public:
252  on_success_policy() noexcept
253  : m_exception_count{uncaught_exception_count()}
254  {
255 
256  }
257 
258  on_success_policy(on_success_policy&&) = default;
259  on_success_policy(const on_success_policy&) = default;
260  on_success_policy& operator=(on_success_policy&&) = default;
261  on_success_policy& operator=(const on_success_policy&) = default;
262 
263  void release() noexcept
264  {
265  m_exception_count = -1;
266  }
267 
268  bool should_execute() const noexcept
269  {
270  return m_exception_count == uncaught_exception_count();
271  }
272 
273  private:
274 
275  int m_exception_count;
276  };
277 
278  //========================================================================
279  // internal non-member functions
280  //========================================================================
281 
282  template<typename T>
283  std::conditional<
284  std::is_nothrow_move_assignable<T>::value,
285  T&&,
286  T const&
287  >
288  move_if_noexcept_assignable(T& x) noexcept
289  {
290  return std::move(x);
291  }
292 
293  template<typename T>
294  const T& as_const(T& t) noexcept { return t; }
295 
296  //========================================================================
297  // internal class : storage
298  //========================================================================
299 
300  template <typename T>
301  class storage
302  {
303  public:
304 
305  template<typename TT, typename Guard>
306  explicit storage(TT&& t, Guard&& guard)
307  : m_value(std::forward<TT>(t))
308  {
309  guard.release();
310  }
311  explicit storage(const T& t)
312  : m_value(t)
313  {
314 
315  }
316  explicit storage(T&& t)
317  : m_value(std::move_if_noexcept(t))
318  {
319 
320  }
321  T& ref() noexcept
322  {
323  return m_value;
324  }
325  const T& cref() const noexcept
326  {
327  return m_value;
328  }
329  T&& rref() noexcept
330  {
331  return std::move(m_value);
332  }
333 
334  void set(const T& t)
335  {
336  m_value = t;
337  }
338  void set(T&& t)
339  {
340  m_value = move_if_noexcept_assignable(t);
341  }
342 
343  private:
344 
345  T m_value;
346  };
347 
348  template <typename T>
349  class storage<T&>
350  {
351  public:
352 
353  template<typename TT, typename Guard>
354  explicit storage(TT&& t, Guard&& guard)
355  : m_value(t)
356  {
357  guard.release();
358  }
359  template<typename TT>
360  explicit storage(TT&& t)
361  : m_value(std::forward<TT>(t))
362  {
363 
364  }
365 
366  T& ref() noexcept
367  {
368  return m_value.get();
369  }
370  const T& cref() const noexcept
371  {
372  return m_value.get();
373  }
374  T& rref() noexcept
375  {
376  return m_value.get();
377  }
378 
379  void set(T& t)
380  {
381  m_value = t;
382  }
383 
384  private:
385 
386  std::reference_wrapper<T> m_value;
387  };
388 
389  //========================================================================
390  // internal class : basic_scope_guard
391  //========================================================================
392 
393  template <typename Fn, typename ExitPolicy>
394  class basic_scope_guard : public ExitPolicy
395  {
396  public:
397  template <typename ExitFunction>
398  explicit basic_scope_guard(ExitFunction&& fn)
399  noexcept(std::is_nothrow_move_constructible<Fn>::value)
400  : ExitPolicy{},
401  m_function{std::forward<ExitFunction>(fn)}
402  {
403 
404  }
405 
406  basic_scope_guard(basic_scope_guard&& other)
407  noexcept(std::is_nothrow_move_constructible<Fn>::value)
408  : ExitPolicy{other},
409  m_function{other.m_function.rref(), other}
410  {
411 
412  }
413 
414  ~basic_scope_guard()
415  noexcept(noexcept(std::declval<Fn&>()()))
416  {
417  if (should_execute()) {
418  m_function.ref()();
419  }
420  }
421 
422  basic_scope_guard(const basic_scope_guard&) = delete;
423  basic_scope_guard& operator=(const basic_scope_guard&) = delete;
424  basic_scope_guard& operator=(basic_scope_guard&&) = delete;
425 
426  //----------------------------------------------------------------------
427  // Modifiers
428  //----------------------------------------------------------------------
429  public:
430 
431  using ExitPolicy::release;
432 
433  //----------------------------------------------------------------------
434  // Observers
435  //----------------------------------------------------------------------
436  public:
437 
438  using ExitPolicy::should_execute;
439 
440  private:
441 
442  storage<Fn> m_function;
443  };
444 
445  } // namespace detail
446 
447  //==========================================================================
448  // class : scope_exit<Fn>
449  //==========================================================================
450 
477  template <typename Fn>
479  : private detail::basic_scope_guard<Fn,detail::on_exit_policy>
480  {
481  using base_type = detail::basic_scope_guard<Fn,detail::on_exit_policy>;
482 
483  public:
484 
485  using base_type::base_type;
486 
487  using base_type::release;
488 
489  using base_type::should_execute;
490  };
491 
492 #if __cplusplus >= 201703L
493  template <typename Fn>
494  scope_exit(Fn) -> scope_exit<Fn>;
495 #endif
496 
497  //==========================================================================
498  // non-member functions : class : scope_exit<Fn>
499  //==========================================================================
500 
501  //--------------------------------------------------------------------------
502  // Utilities
503  //--------------------------------------------------------------------------
504 
519  template <typename Fn>
520  SCOPE_NODISCARD
522  make_scope_exit(Fn&& fn);
523 
524  //==========================================================================
525  // class : scope_success<Fn>
526  //==========================================================================
527 
555  template <typename Fn>
557  : private detail::basic_scope_guard<Fn,detail::on_success_policy>
558  {
559  using base_type = detail::basic_scope_guard<Fn,detail::on_success_policy>;
560 
561  public:
562 
563  using base_type::base_type;
564 
565  using base_type::release;
566 
567  using base_type::should_execute;
568  };
569 
570 #if __cplusplus >= 201703L
571  template <typename Fn>
573 #endif
574 
575  //==========================================================================
576  // non-member functions : class : scope_success<Fn>
577  //==========================================================================
578 
579  //--------------------------------------------------------------------------
580  // Utilities
581  //--------------------------------------------------------------------------
582 
597  template <typename Fn>
598  SCOPE_NODISCARD
600  make_scope_success(Fn&& fn);
601 
602  //==========================================================================
603  // class : scope_fail<Fn>
604  //==========================================================================
605 
633  template <typename Fn>
635  : private detail::basic_scope_guard<Fn,detail::on_fail_policy>
636  {
637  using base_type = detail::basic_scope_guard<Fn,detail::on_fail_policy>;
638 
639  public:
640 
641  using base_type::base_type;
642 
643  using base_type::release;
644 
645  using base_type::should_execute;
646  };
647 
648 #if __cplusplus >= 201703L
649  template <typename Fn>
650  scope_fail(Fn) -> scope_fail<Fn>;
651 #endif
652 
653  //==========================================================================
654  // non-member functions : class : scope_fail<Fn>
655  //==========================================================================
656 
657  //--------------------------------------------------------------------------
658  // Utilities
659  //--------------------------------------------------------------------------
660 
675  template <typename Fn>
676  SCOPE_NODISCARD
678  make_scope_fail(Fn&& fn);
679 
680  //==========================================================================
681  // class : unique_resource<R,D>
682  //==========================================================================
683 
708  template <typename R, typename D>
710  {
711  static_assert(
712  (std::is_move_constructible<R>::value &&
713  std::is_nothrow_move_constructible<R>::value) ||
714  std::is_copy_constructible<R>::value,
715  "unique_resource must be nothrow_move_constructible or copy_constructible"
716  );
717  static_assert(
718  (std::is_move_constructible<R>::value &&
719  std::is_nothrow_move_constructible<D>::value) ||
720  std::is_copy_constructible<D>::value,
721  "deleter must be nothrow_move_constructible or copy_constructible"
722  );
723 
724  template <typename T, typename TT>
725  using is_nothrow_move_or_copy_constructible_from
726  = std::integral_constant<bool,(std::is_reference<TT>::value ||
727  !std::is_nothrow_constructible<T,TT>::value)
728  ? std::is_constructible<T, TT const &>::value
729  : std::is_constructible<T, TT>::value>;
730 
731  template <typename T, typename U, typename TT, typename UU>
732  using enable_constructor_t = typename std::enable_if<
733  is_nothrow_move_or_copy_constructible_from<T,TT>::value &&
734  is_nothrow_move_or_copy_constructible_from<U,UU>::value
735  >::type;
736 
737  //------------------------------------------------------------------------
738  // Constructors / Destructor / Assignment
739  //------------------------------------------------------------------------
740  public:
741 
742  using resource_type = typename std::remove_reference<R>::type;
743  using deleter_type = typename std::remove_reference<D>::type;
744 
745  // Deleted default-constructor
746  unique_resource() = delete;
747 
753  template <typename RR, typename DD,
754  typename = enable_constructor_t<R,D,RR,DD>>
755  explicit unique_resource(RR&& r, DD&& d)
756  noexcept(std::is_nothrow_constructible<R, RR>::value &&
757  std::is_nothrow_constructible<D, DD>::value);
758 
766  noexcept(std::is_nothrow_move_constructible<R>::value &&
767  std::is_nothrow_move_constructible<D>::value);
768 
769  // Deleted copy constructor
770  unique_resource(const unique_resource& other) = delete;
771 
772  //------------------------------------------------------------------------
773 
775  ~unique_resource();
776 
777  //------------------------------------------------------------------------
778 
783  unique_resource& operator=(unique_resource&& other)
784  noexcept(std::is_nothrow_assignable<R&, R>::value &&
785  std::is_nothrow_assignable<D&, D>::value);
786 
787  // Deleted copy assignment
788  unique_resource& operator=(const unique_resource& other) = delete;
789 
790  //------------------------------------------------------------------------
791  // Modifiers
792  //------------------------------------------------------------------------
793  public:
794 
799  void reset() noexcept;
800 
808  template <typename RR>
809  void reset(RR&& r);
810 
817  void release() noexcept;
818 
819  //------------------------------------------------------------------------
820  // Observers
821  //------------------------------------------------------------------------
822  public:
823 
827  const resource_type& get() const noexcept;
828 
832  const deleter_type& get_deleter() const noexcept;
833 
834  template<typename RR=R>
835  typename std::enable_if<std::is_pointer<RR>::value,typename std::remove_pointer<R>::type&>::type
836  operator*() const noexcept;
837 
838  template<typename RR=R>
839  typename std::enable_if<std::is_pointer<RR>::value,R>::type
840  operator->() const noexcept;
841 
842  //------------------------------------------------------------------------
843  // Private Members
844  //------------------------------------------------------------------------
845  private:
846 
847  detail::storage<R> m_resource;
848  detail::storage<D> m_deleter;
849  bool m_execute_on_destruction;
850 
851  //------------------------------------------------------------------------
852  // Private Member Functions
853  //------------------------------------------------------------------------
854  private:
855 
856  template <typename RR, typename DD>
857  unique_resource(RR&& r, DD&& d, bool execute_on_destruction);
858 
859  void do_assign(std::true_type, std::true_type, unique_resource&& other);
860  void do_assign(std::false_type, std::true_type, unique_resource&& other);
861  void do_assign(std::true_type, std::false_type, unique_resource&& other);
862  void do_assign(std::false_type, std::false_type, unique_resource&& other);
863 
864  template <typename T, typename U, typename S>
865  friend unique_resource<typename std::decay<T>::type, typename std::decay<U>::type>
866  make_unique_resource_checked(T&&, const S&, U&&);
867 // noexcept(std::is_nothrow_constructible<typename std::decay<T>::type, T>::value &&
868 // std::is_nothrow_constructible<typename std::decay<U>::type, U>::value);
869 
870  };
871 
872 #if __cplusplus >= 201703L
873 
874  // Template deduction guidelines
875  template<typename R, typename D>
877 
878 #endif /* __cplusplus >= 201703L */
879 
880  //==========================================================================
881  // non-member functions : class : unique_resource<R,D>
882  //==========================================================================
883 
884  //--------------------------------------------------------------------------
885  // Utilities
886  //--------------------------------------------------------------------------
887 
904  template <typename R, typename D, typename S=R>
905  SCOPE_NODISCARD
906  unique_resource<typename std::decay<R>::type, typename std::decay<D>::type>
907  make_unique_resource_checked(R&& resource, const S& invalid, D&& d);
908 // noexcept(std::is_nothrow_constructible<typename std::decay<R>::type, R>::value &&
909 // std::is_nothrow_constructible<typename std::decay<D>::type, D>::value);
910 
929  template <typename R, typename D>
930  SCOPE_NODISCARD
931  unique_resource<typename std::decay<R>::type, typename std::decay<D>::type>
932  make_unique_resource(R&& resource, D&& d)
933  noexcept(std::is_nothrow_constructible<typename std::decay<R>::type, R>::value &&
934  std::is_nothrow_constructible<typename std::decay<D>::type, D>::value);
935 
936 } // namespace scope
937 
938 template <typename Fn>
939 scope::scope_exit<typename std::decay<Fn>::type>
940  scope::make_scope_exit(Fn&& fn)
941 {
942  using result_type = scope_exit<typename std::decay<Fn>::type>;
943 
944  return result_type{std::forward<Fn>(fn)};
945 }
946 
947 template <typename Fn>
949  scope::make_scope_success(Fn&& fn)
950 {
951  using result_type = scope_success<typename std::decay<Fn>::type>;
952 
953  return result_type{std::forward<Fn>(fn)};
954 }
955 
956 template <typename Fn>
958  scope::make_scope_fail(Fn&& fn)
959 {
960  using result_type = scope_fail<typename std::decay<Fn>::type>;
961 
962  return result_type{std::forward<Fn>(fn)};
963 }
964 
965 //============================================================================
966 // definition : class : unique_resource
967 //============================================================================
968 
969 //----------------------------------------------------------------------------
970 // Constructors / Destructor / Assignment
971 //----------------------------------------------------------------------------
972 
973 template <typename R, typename D>
974 template <typename RR, typename DD, typename>
976  noexcept(std::is_nothrow_constructible<R, RR>::value &&
977  std::is_nothrow_constructible<D, DD>::value)
978  : unique_resource{std::forward<RR>(r), std::forward<DD>(d), true}
979 {
980 
981 }
982 
983 template <typename R, typename D>
985  noexcept(std::is_nothrow_move_constructible<R>::value &&
986  std::is_nothrow_move_constructible<D>::value)
987  : m_resource{other.m_resource.rref(), make_scope_exit([]{})},
988  m_deleter{other.m_deleter.rref(), make_scope_exit([&other,this]
989  {
990  if (other.m_execute_on_destruction) {
991  auto& deleter = m_deleter.ref();
992  deleter(m_resource.ref());
993  other.release();
994  }
995  })},
996  m_execute_on_destruction{other.m_execute_on_destruction}
997 {
998  other.m_execute_on_destruction = false;
999 }
1000 //----------------------------------------------------------------------------
1001 
1002 template <typename R, typename D>
1004 {
1005  reset();
1006 }
1007 
1008 //----------------------------------------------------------------------------
1009 
1010 template <typename R, typename D>
1013  noexcept(std::is_nothrow_assignable<R&, R>::value &&
1014  std::is_nothrow_assignable<D&, D>::value)
1015 {
1016  if (&other == this ) return (*this);
1017 
1018  do_assign(
1019  std::is_nothrow_move_assignable<R>{},
1020  std::is_nothrow_move_assignable<D>{},
1021  std::move(other)
1022  );
1023  m_execute_on_destruction = other.m_execute_on_destruction;
1024  other.m_execute_on_destruction = false;
1025  return (*this);
1026 }
1027 
1028 //----------------------------------------------------------------------------
1029 // Modifiers
1030 //----------------------------------------------------------------------------
1031 
1032 template <typename R, typename D>
1034  noexcept
1035 {
1036  if (m_execute_on_destruction) {
1037  m_execute_on_destruction = false;
1038 
1039  auto& deleter = m_deleter.ref();
1040  deleter( m_resource.ref() );
1041  }
1042 }
1043 
1044 template <typename R, typename D>
1045 template <typename RR>
1046 inline void scope::unique_resource<R,D>::reset(RR&& r)
1047 {
1048  auto guard = make_scope_fail([&r, this]{
1049  auto& deleter = m_deleter.ref();
1050  deleter(r);
1051  });
1052  (void) guard;
1053 
1054  reset();
1055  m_resource.set( std::forward<RR>(r) );
1056  m_execute_on_destruction = true;
1057 }
1058 
1059 
1060 template <typename R, typename D>
1062  noexcept
1063 {
1064  m_execute_on_destruction = false;
1065 }
1066 
1067 //----------------------------------------------------------------------------
1068 // Observers
1069 //----------------------------------------------------------------------------
1070 
1071 template <typename R, typename D>
1072 inline const typename scope::unique_resource<R,D>::resource_type&
1074  const noexcept
1075 {
1076  return m_resource.cref();
1077 }
1078 
1079 template <typename R, typename D>
1080 inline const typename scope::unique_resource<R,D>::deleter_type&
1082  const noexcept
1083 {
1084  return m_deleter.cref();
1085 }
1086 
1087 template <typename R, typename D>
1088 template<typename RR>
1089 inline typename std::enable_if<std::is_pointer<RR>::value,typename std::remove_pointer<R>::type&>::type
1091  const noexcept
1092 {
1093  return (*get());
1094 }
1095 
1096 template <typename R, typename D>
1097 template<typename RR>
1098 inline typename std::enable_if<std::is_pointer<RR>::value,R>::type
1100  const noexcept
1101 {
1102  return get();
1103 }
1104 
1105 
1106 //----------------------------------------------------------------------------
1107 // Private Member Functions
1108 //----------------------------------------------------------------------------
1109 
1110 template <typename R, typename D>
1111 template <typename RR, typename DD>
1113  DD&& d,
1114  bool execute_on_destruction)
1115  : m_resource{std::forward<RR>(r), make_scope_exit([&d,&r]
1116  {
1117  d(r);
1118  })},
1119  m_deleter{std::forward<DD>(d), make_scope_exit([&d,this]{
1120  d(m_resource.ref());
1121  })},
1122  m_execute_on_destruction{execute_on_destruction}
1123 {
1124 
1125 }
1126 
1127 //----------------------------------------------------------------------------
1128 
1129 template <typename R, typename D>
1130 inline void scope::unique_resource<R,D>::do_assign(std::true_type,
1131  std::true_type,
1132  unique_resource&& other)
1133 {
1134  m_resource = std::move(other.resource);
1135  m_deleter = std::move(other.deleter);
1136 }
1137 
1138 template <typename R, typename D>
1139 inline void scope::unique_resource<R,D>::do_assign(std::false_type,
1140  std::true_type,
1141  unique_resource&& other)
1142 {
1143  m_resource = detail::as_const(other.resource);
1144  m_deleter = std::move(other.deleter);
1145 }
1146 
1147 template <typename R, typename D>
1148 inline void scope::unique_resource<R,D>::do_assign(std::true_type,
1149  std::false_type,
1150  unique_resource&& other)
1151 {
1152  m_resource = std::move(other.resource);
1153  m_deleter = detail::as_const(other.deleter);
1154 }
1155 
1156 template <typename R, typename D>
1157 inline void scope::unique_resource<R,D>::do_assign(std::false_type,
1158  std::false_type,
1159  unique_resource&& other)
1160 {
1161  m_resource = detail::as_const(other.resource);
1162  m_deleter = detail::as_const(other.deleter);
1163 }
1164 
1165 //============================================================================
1166 // definitions : non-member functions : class : unique_resource
1167 //============================================================================
1168 
1169 //----------------------------------------------------------------------------
1170 // Utilities
1171 //----------------------------------------------------------------------------
1172 
1173 template <typename R, typename D, typename S>
1174 inline scope::unique_resource<typename std::decay<R>::type, typename std::decay<D>::type>
1175  scope::make_unique_resource_checked(R&& resource, const S& invalid, D&& d)
1176 // noexcept(std::is_nothrow_constructible<typename std::decay<R>::type, R>::value &&
1177 // std::is_nothrow_constructible<typename std::decay<D>::type, D>::value)
1178 {
1179  using resource_type = typename std::decay<R>::type;
1180  using deleter_type = typename std::decay<D>::type;
1182 
1183  const auto execute_on_destruction = !(resource == invalid);
1184 
1185  return result_type{
1186  std::forward<R>(resource),
1187  std::forward<D>(d),
1188  execute_on_destruction
1189  };
1190 }
1191 
1192 template <typename R, typename D>
1193 inline scope::unique_resource<typename std::decay<R>::type, typename std::decay<D>::type>
1194  scope::make_unique_resource(R&& resource, D&& d)
1195  noexcept(std::is_nothrow_constructible<typename std::decay<R>::type, R>::value &&
1196  std::is_nothrow_constructible<typename std::decay<D>::type, D>::value)
1197 {
1198  using resource_type = typename std::decay<R>::type;
1199  using deleter_type = typename std::decay<D>::type;
1201 
1202  return result_type{
1203  std::forward<R>(resource),
1204  std::forward<D>(d)
1205  };
1206 }
1207 
1208 #endif /* SCOPE_SCOPE_HPP */
const deleter_type & get_deleter() const noexcept
Gets a reference to the underlying deleter.
An exit handler for handling throwing cases.
Definition: scope.hpp:634
A resource with unique-ownership semantics.
Definition: scope.hpp:709
~unique_resource()
Equivalent to invoking reset()
An exit handler for handling both sucess an error cases.
Definition: scope.hpp:478
const resource_type & get() const noexcept
Gets a reference to the underlying resource.
void release() noexcept
Releases the underlying stored resource from being managed by this unique_resource class...
An exit handler for handling non-throwing cases.
Definition: scope.hpp:556
unique_resource & operator=(unique_resource &&other) noexcept(std::is_nothrow_assignable< R &, R >::value &&std::is_nothrow_assignable< D &, D >::value)
void reset() noexcept
Resets the resource managed by this unique_resource.