You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 line
4.6 KiB

  1. #pragma once
  2. #include <memory>
  3. #include <cpputils/misc/exception.h>
  4. #include <cpputils/mp/core.h>
  5. namespace utl
  6. {
  7. template<class T>
  8. struct smart_ptr
  9. {
  10. private:
  11. template<class Tt_base, class Tt_derived>
  12. using cop_is_base_of = std::is_base_of<mp::clean_type<Tt_base>, mp::clean_type<Tt_derived>>;
  13. template<class X, class Enable = void>
  14. struct __impl_cop_is_value :
  15. public mp::c_true;
  16. template<class X>
  17. struct __impl_cop_is_value<X*, void> :
  18. public mp::c_false;
  19. template<template<class> class F, class X>
  20. struct __impl_cop_is_value<F<X>, mp::enable_if<cop_is_base_of<smart_ptr<X>, F<X>>>> :
  21. public mp::c_false;
  22. template<class X>
  23. struct __impl_cop_is_value<std::reference_wrapper<X>, void> :
  24. public mp::c_false;
  25. template<class X>
  26. using cop_is_value = __impl_cop_is_value<mp::clean_type<X>>;
  27. struct op_deleter_noop
  28. { inline void operator()(T*) { } };
  29. private:
  30. std::shared_ptr<T> _value;
  31. public:
  32. inline bool has_value() const
  33. { return static_cast<bool>(_value); }
  34. inline T& value()
  35. {
  36. if (!_value)
  37. throw utl::invalid_operation_exception("smart_ptr does not have a value");
  38. return *_value;
  39. }
  40. inline const T& value() const
  41. {
  42. if (!_value)
  43. throw utl::invalid_operation_exception("smart_ptr does not have a value");
  44. return *_value;
  45. }
  46. inline T& operator*()
  47. { return value(); }
  48. inline const T& operator*() const
  49. { return value(); }
  50. inline T* operator->()
  51. { return &value(); }
  52. inline const T* operator->() const
  53. { return &value(); }
  54. inline operator bool() const
  55. { return has_value(); }
  56. inline smart_ptr& reset()
  57. {
  58. _value.reset();
  59. return *this;
  60. }
  61. template<class X = T, mp::enable_if_c<cop_is_value<X>::value, int> = 0>
  62. inline smart_ptr& reset(X& x)
  63. {
  64. _value.reset(new X(x));
  65. return *this;
  66. }
  67. template<class X = T, mp::enable_if_c<cop_is_value<X>::value, int> = 0>
  68. inline smart_ptr& reset(X&& x)
  69. {
  70. _value.reset(new X(std::move(x)));
  71. return *this;
  72. }
  73. template<class X = T, mp::enable_if_c<cop_is_base_of<T, X>::value, int> = 0>
  74. inline smart_ptr& reset(const smart_ptr<X>& other)
  75. {
  76. _value = other._value;
  77. return *this;
  78. }
  79. template<class X = T, mp::enable_if_c<cop_is_base_of<T, X>::value, int> = 0>
  80. inline smart_ptr& reset(smart_ptr<X>&& other)
  81. {
  82. _value = std::move(other._value);
  83. return *this;
  84. }
  85. template<class X = T, mp::enable_if_c<cop_is_base_of<T, X>::value, int> = 0>
  86. inline smart_ptr& reset(std::reference_wrapper<X>&& ref)
  87. {
  88. _value.reset(&ref.get(), op_deleter_noop());
  89. return *this;
  90. }
  91. template<class... Args>
  92. inline smart_ptr& reset(Args&&... args)
  93. {
  94. _value.reset(new T(std::forward<Args>(args)...));
  95. return *this;
  96. }
  97. template<class X = T>
  98. inline smart_ptr& operator=(X&& x)
  99. { return reset(std::forward<X>(x)); }
  100. smart_ptr()
  101. { }
  102. template<class X = T, mp::enable_if_c<cop_is_value<X>::value, int> = 0>
  103. smart_ptr(X& x) :
  104. _value(new X(x))
  105. { }
  106. template<class X = T, mp::enable_if_c<cop_is_value<X>::value, int> = 0>
  107. smart_ptr(X&& x) :
  108. _value(new X(std::move(x)))
  109. { }
  110. template<class X = T, mp::enable_if_c<std::is_base_of<T, X>::value, int> = 0>
  111. smart_ptr(X* x) :
  112. _value(x)
  113. { }
  114. template<class X = T, mp::enable_if_c<std::is_base_of<T, X>::value, int> = 0>
  115. smart_ptr(const smart_ptr<X>& other) :
  116. _value(other._value)
  117. { }
  118. template<class X = T, mp::enable_if_c<std::is_base_of<T, X>::value, int> = 0>
  119. smart_ptr(smart_ptr<X>&& other) :
  120. _value(std::move(other._value))
  121. { }
  122. template<class X = T, mp::enable_if_c<std::is_base_of<T, X>::value, int> = 0>
  123. smart_ptr(std::reference_wrapper<X>&& ref) :
  124. _value(&ref.get(), op_deleter_noop())
  125. { }
  126. template<class... Args>
  127. smart_ptr(Args... args) :
  128. _value(new T(args...))
  129. { }
  130. };
  131. }