PStack  2.0
Stack trace printer for MSVC and GCC binaries
unique_handle.hpp
Go to the documentation of this file.
1 // ===-- include/psystem/framework/unique_handle.hpp ------ -*- C++ -*- --=== //
2 // Copyright (c) 2014 Matt Bisson. All rights reserved.
3 
33 #pragma once
34 #ifndef PSYSTEM_FRAMEWORK_UNIQUE_HANDLE_HPP
35 #define PSYSTEM_FRAMEWORK_UNIQUE_HANDLE_HPP
36 
37 #include "platform.hpp"
38 
39 #include "default_close_handle.hpp"
40 #include "managed_handle_proxy.hpp"
41 #include "stack_allocated.hpp"
42 
43 namespace psystem {
44 
45 // -----------------------------------------------------------------------------
46 // Internal class template for unique_handle's deleterless API
47 // -----------------------------------------------------------------------------
48 
75 template <typename T, typename D, T kInvalidHandle>
77 {
80  template <typename T2, typename, T2 kInvalidHandle2>
81  friend class unique_handle;
82 
86 public:
88  using deleter_type = D;
89 
91  using handle_type = T;
92 
96 public:
98 #ifndef _MSC_VER
99  static constexpr T invalid_handle_value = kInvalidHandle;
100 #endif
101 
105 private:
114  : m_handle(handle) { }
115 
119 public:
121  unique_handle_impl(unique_handle_impl const&) = delete;
122 
125 
129 public:
134  handle_type get() const noexcept
135  {
136  return m_handle;
137  }
138 
150  {
151  handle_type handle = m_handle;
152  m_handle = kInvalidHandle;
153  return handle;
154  }
155 
159 public:
171  explicit operator bool() const noexcept
172  {
173  return m_handle != kInvalidHandle;
174  }
175 
179 private:
182 };
183 
184 // -----------------------------------------------------------------------------
185 // Public-facing unique_handle class template
186 // -----------------------------------------------------------------------------
187 
245 template <
246  typename T = HANDLE,
247  typename D = default_close_handle<T>,
248  T kInvalidHandle = INVALID_HANDLE_VALUE>
250  : public unique_handle_impl<T, D, kInvalidHandle>
251 {
255 private:
258 public:
259  using typename base::deleter_type;
260  using typename base::handle_type;
261 
264  using safe_address_container =
266  handle_type,
268  >;
269 
273 public:
274 #ifndef _MSC_VER
275  using base::invalid_handle_value;
276 #endif
277 
281 public:
296  explicit unique_handle(handle_type hndl = kInvalidHandle) noexcept
297  : base(hndl),
298  m_deleter()
299  { }
300 
324  template <typename D2>
325  unique_handle(handle_type hndl, D2&& deleter) noexcept
326  : base(hndl),
327  m_deleter(std::forward<D2>(deleter))
328  { }
329 
347  : base(other.release()),
348  m_deleter(std::move(other.m_deleter))
349  { }
350 
362  {
363  if (kInvalidHandle != this->m_handle)
364  {
365  m_deleter(this->m_handle);
366 #ifdef _DEBUG
367  this->m_handle = kInvalidHandle;
368 #endif
369  }
370  }
371 
375 public:
391  {
392  // Since we've overloaded the operator& for this class, our incoming
393  // variable is basically unreference-able... until C++11. See
394  // std::addressof()!
395  if (std::addressof(o) == this) return *this;
396 
397  reset(o.release());
398 
399  m_deleter = std::forward<deleter_type>(o.m_deleter);
400  return *this;
401  }
402 
413  {
414  return safe_address_container(*this);
415  }
416 
420 public:
430  {
431  return m_deleter;
432  }
433 
444  {
445  return m_deleter;
446  }
447 
461  void reset(handle_type hndl = kInvalidHandle) noexcept
462  {
463  if (hndl == this->m_handle) return;
464 
465  if (kInvalidHandle != this->m_handle)
466  {
467  m_deleter(this->m_handle);
468  }
469  this->m_handle = hndl;
470  }
471 
484  {
486 
487  // This would be a pointless swap.
488  if (UNLIKELY(&o == this)) return;
489 
490  // Make temp copies
491  handle_type tmp_handle = o.m_handle;
492  deleter_type tmp_deleter = std::move(o.m_deleter);
493 
494  // Make o valid
495  o.m_handle = this->m_handle;
496  o.m_deleter = std::move(m_deleter);
497 
498  // Make *this valid
499  this->m_handle = tmp_handle;
500  m_deleter = std::move(tmp_deleter);
501  }
502 
506 private:
509 };
510 
511 // -----------------------------------------------------------------------------
512 // Partial specialization to eliminate storage for deleter_type.
513 // -----------------------------------------------------------------------------
514 
535 template <typename T, T kInvalidHandle>
536 class unique_handle<T, default_close_handle<T>, kInvalidHandle>
537  : public unique_handle_impl<T, default_close_handle<T>, kInvalidHandle>
538 {
542 private:
545 public:
546  using typename base::deleter_type;
547  using typename base::handle_type;
548 
551  using safe_address_container =
553  handle_type,
555  >;
556 
560 public:
561 #ifndef _MSC_VER
562  using base::invalid_handle_value;
563 #endif
564 
568 public:
579  explicit unique_handle(handle_type hndl = kInvalidHandle) noexcept
580  : base(hndl)
581  { }
582 
597  : base(other.release())
598  { }
599 
608  {
609  if (kInvalidHandle != this->m_handle)
610  {
612 #ifdef _DEBUG
613  this->m_handle = kInvalidHandle;
614 #endif
615  }
616  }
617 
621 public:
624  {
625  reset(o.release());
626  return *this;
627  }
628 
631  {
632  return safe_address_container(*this);
633  }
634 
638 public:
640  void reset(handle_type hndl = kInvalidHandle) noexcept
641  {
642  if (hndl == this->m_handle) return;
643 
644  if (kInvalidHandle != this->m_handle)
645  {
647  }
648  this->m_handle = hndl;
649  }
650 
659  {
660  // This would be a pointless swap.
661  if (UNLIKELY(&o == this)) return;
662 
663  handle_type tmp_handle = o.m_handle;
664  o.m_handle = this->m_handle;
665  this->m_handle = tmp_handle;
666  }
667 };
668 
669 } // namespace psystem
670 
671 // -----------------------------------------------------------------------------
672 // Template specializations injected into the std namespace
673 // -----------------------------------------------------------------------------
674 
675 namespace std {
676 
690 template <typename T, typename D, T kInvalidHandle>
691 void
692 swap(
695  noexcept
696 {
697  o1.swap(o2);
698 }
699 
710 template <typename T, typename D, T kInvalidHandle>
711 struct hash< psystem::unique_handle<T, D, kInvalidHandle> >
712 {
715 
719  size_t operator()(unique_handle_type const& value) const
720  {
721  return std::hash<typename unique_handle_type::handle_type>()(
722  value.get());
723  }
724 };
725 
726 } // namespace std
727 
728 // -----------------------------------------------------------------------------
729 // Free functions related to unique_handle
730 // -----------------------------------------------------------------------------
731 
746 template <typename T, typename D, T kInvalidHandle>
747 inline bool operator==(
750 {
751  return (h1.get() == h2.get());
752 }
753 
770 template <typename T, typename D, T kInvalidHandle>
771 inline bool operator!=(
774 {
775  return !(h1 == h2);
776 }
777 
794 template <typename T, typename D, T kInvalidHandle>
795 inline bool operator<(
798 {
799  return std::less<
801  h1.get(), h2.get());
802 }
803 
820 template <typename T, typename D, T kInvalidHandle>
821 inline bool operator<=(
824 {
825  return !(h2 < h1);
826 }
827 
844 template <typename T, typename D, T kInvalidHandle>
845 inline bool operator>(
848 {
849  return (h2 < h1);
850 }
851 
868 template <typename T, typename D, T kInvalidHandle>
869 inline bool operator>=(
872 {
873  return !(h1 < h2);
874 }
875 
876 #endif // PSYSTEM_FRAMEWORK_UNIQUE_HANDLE_HPP
D deleter_type
The data-type of the clean-up facility.
Definition: unique_handle.hpp:88
void swap(unique_handle &o) noexcept
Swap ownership of two unique_handle instances.
Definition: unique_handle.hpp:483
A simple functor to close handles (for use with RAII handle containers).
Definition: default_close_handle.hpp:49
Master header file for Platform-wide declarations.
Uniquely manage a single "handle".
Definition: unique_handle.hpp:249
unique_handle(unique_handle &&other) noexcept
Transfer ownership of a handle from another unique_handle.
Definition: unique_handle.hpp:346
T m_handle
A temporary handle for tracking changes while accessed as a pointer-to-handle type.
Definition: managed_handle_proxy.hpp:96
void swap(unique_handle &o) noexcept
Swap ownership of two unique_handle instances.
Definition: unique_handle.hpp:658
Definition: shared_handle.hpp:782
unique_handle(handle_type hndl=kInvalidHandle) noexcept
Construct an instance to manage a handle.
Definition: unique_handle.hpp:579
Disable heap allocation and deallocation.
Definition: stack_allocated.hpp:42
#define noexcept
Replace keyword with something useful.
Definition: platform.hpp:71
Base unique_handle functionality common to all template specializations.
Definition: unique_handle.hpp:76
deleter_type m_deleter
The instance that will be used to clean up the handle's resources.
Definition: unique_handle.hpp:508
size_t operator()(unique_handle_type const &value) const
Invoke the hash functor.
Definition: unique_handle.hpp:719
~unique_handle() noexcept
Destroy this container, freeing the handle managed within.
Definition: unique_handle.hpp:607
bool operator<(psystem::unique_handle< T, D, kInvalidHandle > const &h1, psystem::unique_handle< T, D, kInvalidHandle > const &h2) noexcept
Test if the first handle is less than the second.
Definition: unique_handle.hpp:795
unique_handle_impl(handle_type handle) noexcept
Construct this base container object with a handle.
Definition: unique_handle.hpp:113
#define UNLIKELY(cond)
Alters branch prediction in generated code to favor a false result.
Definition: platform.hpp:105
T handle_type
The data-type of the handle being managed.
Definition: unique_handle.hpp:91
Allows safe modification of a managed handle container when accessed by the handle's address...
Definition: managed_handle_proxy.hpp:51
D deleter_type
The data-type of the clean-up facility.
Definition: unique_handle.hpp:88
void reset(handle_type hndl=kInvalidHandle) noexcept
Assign a new handle to be managed by this instance.
Definition: unique_handle.hpp:461
unique_handle & operator=(unique_handle &&o) noexcept
Transfer ownership of a handle into this instance.
Definition: unique_handle.hpp:623
~unique_handle() noexcept
Destroy this container, freeing the handle managed within.
Definition: unique_handle.hpp:361
unique_handle & operator=(unique_handle &&o) noexcept
Transfer ownership of a handle into this instance.
Definition: unique_handle.hpp:390
bool operator==(psystem::unique_handle< T, D, kInvalidHandle > const &h1, psystem::unique_handle< T, D, kInvalidHandle > const &h2) noexcept
Test for equality of two handles.
Definition: unique_handle.hpp:747
deleter_type & get_deleter() noexcept
Access the deleter instance within this class.
Definition: unique_handle.hpp:429
handle_type get() const noexcept
Access the handle contained in this object.
Definition: unique_handle.hpp:134
safe_address_container operator&() noexcept
Allow safe alteration of the handle by routines that return data by C-style output parameters...
Definition: unique_handle.hpp:630
T handle_type
The data-type of the handle being managed.
Definition: unique_handle.hpp:91
bool operator!=(psystem::unique_handle< T, D, kInvalidHandle > const &h1, psystem::unique_handle< T, D, kInvalidHandle > const &h2) noexcept
Test for inequality of two handles.
Definition: unique_handle.hpp:771
unique_handle(handle_type hndl=kInvalidHandle) noexcept
Construct an instance to manage a handle.
Definition: unique_handle.hpp:296
safe_address_container operator&() noexcept
Allow safe alteration of the handle by routines that return data by C-style output parameters...
Definition: unique_handle.hpp:412
Introduces a functor to wrap CloseHandle() for RAII handle containers.
handle_type release() noexcept
Release the handle from being managed by this class.
Definition: unique_handle.hpp:149
static void close_handle(T hndl) noexcept
Executes a handle clean-up routine without requiring an instance.
Definition: default_close_handle.hpp:64
unique_handle(unique_handle &&other) noexcept
Transfer ownership of a handle from another unique_handle.
Definition: unique_handle.hpp:596
Contains the process examination "system" and basic frameworks.
Definition: pstack_event_handler.hpp:28
#define constexpr
Replace keyword with something useful.
Definition: platform.hpp:70
Provide an internal class for safely altering a managed handle by address within its container...
bool operator>=(psystem::unique_handle< T, D, kInvalidHandle > const &h1, psystem::unique_handle< T, D, kInvalidHandle > const &h2) noexcept
Test if the first handle is greater than or equal to the second.
Definition: unique_handle.hpp:869
unique_handle(handle_type hndl, D2 &&deleter) noexcept
Construct an instance to manage a handle with a custom "deleter.".
Definition: unique_handle.hpp:325
deleter_type const & get_deleter() const noexcept
Access the const deleter instance within this class.
Definition: unique_handle.hpp:443
void reset(handle_type hndl=kInvalidHandle) noexcept
Assign a new handle to be managed by this instance.
Definition: unique_handle.hpp:640
bool operator>(psystem::unique_handle< T, D, kInvalidHandle > const &h1, psystem::unique_handle< T, D, kInvalidHandle > const &h2) noexcept
Test if the first handle is greater than the second.
Definition: unique_handle.hpp:845
Defines the psystem::stack_allocated interface.
bool operator<=(psystem::unique_handle< T, D, kInvalidHandle > const &h1, psystem::unique_handle< T, D, kInvalidHandle > const &h2) noexcept
Test if the first handle is less than or equal to the second.
Definition: unique_handle.hpp:821
psystem::internal::managed_handle_proxy< handle_type, unique_handle< handle_type, deleter_type, kInvalidHandle > > safe_address_container
A safe container for altering the handle by the address-of operator.
Definition: unique_handle.hpp:268
unique_handle_impl & operator=(unique_handle_impl &)=delete
Disable copy-assignment to prevent double-frees.
handle_type m_handle
The handle that will be managed by this class.
Definition: unique_handle.hpp:181