Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

160 řádky
3.9 KiB

  1. #pragma once
  2. #include <memory>
  3. #include <type_traits>
  4. #include <cpputils/misc/string.h>
  5. #include <cpputils/misc/exception.h>
  6. namespace utl
  7. {
  8. template<class T>
  9. struct nullable
  10. {
  11. public:
  12. using value_type = T;
  13. using clean_type = typename std::remove_reference<T>::type;
  14. using pointer_type = clean_type*;
  15. private:
  16. struct container
  17. {
  18. value_type value;
  19. template<class... Args>
  20. container(Args&&... args) :
  21. value(std::forward<Args>(args)...)
  22. { }
  23. };
  24. private:
  25. std::unique_ptr<container> _container;
  26. inline void check() const
  27. {
  28. if (!_container)
  29. throw invalid_operation_exception("nullable does not have a value");
  30. }
  31. public:
  32. inline value_type& value()
  33. { check(); return _container->value; }
  34. inline const value_type& value() const
  35. { check(); return _container->value; }
  36. inline bool has_value() const
  37. { return static_cast<bool>(_container); }
  38. inline void reset()
  39. { _container.reset(); }
  40. inline auto& operator*()
  41. { return value(); }
  42. inline auto& operator*() const
  43. { return value(); }
  44. inline auto* operator->()
  45. { return &value(); }
  46. inline auto* operator->() const
  47. { return &value(); }
  48. inline value_type& operator()()
  49. { return value(); }
  50. inline auto& operator()() const
  51. { return value(); }
  52. inline explicit operator bool() const
  53. { return has_value(); }
  54. inline bool operator==(T v) const
  55. { return has_value() && value() == v; }
  56. inline bool operator==(const nullable& other) const
  57. { return has_value() && other.has_value() && value() == other.value(); }
  58. inline bool operator<(const nullable& other) const
  59. {
  60. return this->has_value()
  61. && other.has_value()
  62. && value() < other.value();
  63. }
  64. inline bool operator>(const nullable& other) const
  65. {
  66. return this->has_value()
  67. && other.has_value()
  68. && value() < other.value();
  69. }
  70. inline bool operator<=(const nullable& other) const
  71. {
  72. return this->has_value()
  73. && other.has_value()
  74. && value() < other.value();
  75. }
  76. inline bool operator>=(const nullable& other) const
  77. {
  78. return this->has_value()
  79. && other.has_value()
  80. && value() < other.value();
  81. }
  82. inline void operator=(value_type&& t)
  83. { _container.reset(new container(std::forward<value_type>(t))); }
  84. inline void operator=(const nullable& other)
  85. {
  86. if (other.has_value())
  87. *this = other.value();
  88. else
  89. reset();
  90. }
  91. inline void operator=(nullable&& other)
  92. { _container = std::move(other._container); }
  93. nullable()
  94. { }
  95. template<class... Args>
  96. nullable(Args&&... args) :
  97. _container(new container(std::forward<Args>(args)...))
  98. { }
  99. nullable(nullable& other)
  100. { if (static_cast<bool>(other)) *this = other(); }
  101. nullable(const nullable& other)
  102. { if (static_cast<bool>(other)) *this = other(); }
  103. nullable(nullable&& other) :
  104. _container(std::move(other._container))
  105. { }
  106. };
  107. namespace __impl
  108. {
  109. template<class T>
  110. struct op_to_string<nullable<T>, void>
  111. {
  112. inline void operator()(std::ostream& os, const nullable<T>& s) const
  113. {
  114. if (s.has_value())
  115. op_to_string<T>()(os, s.value());
  116. else
  117. os << "null";
  118. }
  119. };
  120. }
  121. }