1 #pragma once
2 
3 
4 #include <memory>
5 #include <type_traits>
6 #include <utility>
7 #include "loop.hpp"
8 
9 
10 namespace uvw {
11 
12 
13 /**
14  * @brief Wrapper class for underlying types.
15  *
16  * It acts mainly as a wrapper around data structures of the underlying library.
17  */
18 template<typename T, typename U>
19 class UnderlyingType {
20     template<typename, typename>
21     friend class UnderlyingType;
22 
23 protected:
ConstructorAccessuvw::UnderlyingType::ConstructorAccess24     struct ConstructorAccess { explicit ConstructorAccess(int) {} };
25 
get()26     auto get() noexcept {
27         return &resource;
28     }
29 
get() const30     auto get() const noexcept {
31         return &resource;
32     }
33 
34     template<typename R>
get()35     auto get() noexcept {
36         static_assert(not std::is_same<R, U>::value, "!");
37         return reinterpret_cast<R *>(&resource);
38     }
39 
40     template<typename R, typename... P>
get(UnderlyingType<P...> & other)41     auto get(UnderlyingType<P...> &other) noexcept {
42         return reinterpret_cast<R *>(&other.resource);
43     }
44 
45     template<typename R>
get() const46     auto get() const noexcept {
47         static_assert(not std::is_same<R, U>::value, "!");
48         return reinterpret_cast<const R *>(&resource);
49     }
50 
51     template<typename R, typename... P>
get(const UnderlyingType<P...> & other) const52     auto get(const UnderlyingType<P...> &other) const noexcept {
53         return reinterpret_cast<const R *>(&other.resource);
54     }
55 
56 public:
UnderlyingType(ConstructorAccess,std::shared_ptr<Loop> ref)57     explicit UnderlyingType(ConstructorAccess, std::shared_ptr<Loop> ref) noexcept
58         : pLoop{std::move(ref)}, resource{}
59     {}
60 
61     UnderlyingType(const UnderlyingType &) = delete;
62     UnderlyingType(UnderlyingType &&) = delete;
63 
~UnderlyingType()64     virtual ~UnderlyingType() {
65         static_assert(std::is_base_of<UnderlyingType<T, U>, T>::value, "!");
66     }
67 
68     UnderlyingType & operator=(const UnderlyingType &) = delete;
69     UnderlyingType & operator=(UnderlyingType &&) = delete;
70 
71     /**
72      * @brief Creates a new resource of the given type.
73      * @param args Arguments to be forwarded to the actual constructor (if any).
74      * @return A pointer to the newly created resource.
75      */
76     template<typename... Args>
create(Args &&...args)77     static std::shared_ptr<T> create(Args&&... args) {
78         return std::make_shared<T>(ConstructorAccess{0}, std::forward<Args>(args)...);
79     }
80 
81     /**
82      * @brief Gets the loop from which the resource was originated.
83      * @return A reference to a loop instance.
84      */
loop() const85     Loop & loop() const noexcept { return *pLoop; }
86 
87     /**
88      * @brief Gets the underlying raw data structure.
89      *
90      * This function should not be used, unless you know exactly what you are
91      * doing and what are the risks.<br/>
92      * Going raw is dangerous, mainly because the lifetime management of a loop,
93      * a handle or a request is in charge to the library itself and users should
94      * not work around it.
95      *
96      * @warning
97      * Use this function at your own risk, but do not expect any support in case
98      * of bugs.
99      *
100      * @return The underlying raw data structure.
101      */
raw() const102     const U * raw() const noexcept {
103         return &resource;
104     }
105 
106     /**
107      * @brief Gets the underlying raw data structure.
108      *
109      * This function should not be used, unless you know exactly what you are
110      * doing and what are the risks.<br/>
111      * Going raw is dangerous, mainly because the lifetime management of a loop,
112      * a handle or a request is in charge to the library itself and users should
113      * not work around it.
114      *
115      * @warning
116      * Use this function at your own risk, but do not expect any support in case
117      * of bugs.
118      *
119      * @return The underlying raw data structure.
120      */
raw()121     U * raw() noexcept {
122         return const_cast<U *>(const_cast<const UnderlyingType *>(this)->raw());
123     }
124 
125 private:
126     std::shared_ptr<Loop> pLoop;
127     U resource;
128 };
129 
130 
131 }
132