1 /*
2  * Copyright (c) 2014-2019, Nils Christopher Brause, Philipp Kerling
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  *    list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #ifndef WAYLAND_UTIL_HPP
27 #define WAYLAND_UTIL_HPP
28 
29 #include <algorithm>
30 #include <memory>
31 #include <stdexcept>
32 #include <string>
33 #include <typeinfo>
34 #include <utility>
35 #include <vector>
36 
37 #include <wayland-client-core.h>
38 
39 #define wl_array_for_each_cpp(pos, array)                                                         \
40   for ((pos) = static_cast<decltype(pos)>((array)->data);                                         \
41        reinterpret_cast<const char*>(pos) < (reinterpret_cast<const char*>((array)->data) + (array)->size); \
42        (pos)++)
43 
44 namespace wayland
45 {
46   class proxy_t;
47 
48   class array_t;
49 
50   namespace detail
51   {
52     /** \brief Check the return value of a C function and throw exception on
53      *         failure
54      *
55      * \param return_value return value of the function to check
56      * \param function_name name of the function, for error message
57      * \return return_value if it was >= 0
58      * \exception std::system_error with errno if return_value < 0
59      */
60     int check_return_value(int return_value, std::string const &function_name);
61 
62     /** \brief Non-refcounted wrapper for C objects
63      *
64      * This is by default copyable. If this is not desired, delete the
65      * copy constructor and copy assignment operator in derived classes.
66      */
67     template<typename native_t>
68     class basic_wrapper
69     {
70     private:
71       native_t *object = nullptr;
72 
73     protected:
basic_wrapper(native_t * object)74       basic_wrapper(native_t *object)
75       : object{object}
76       {
77       }
78 
79     public:
80       basic_wrapper() = default;
81       ~basic_wrapper() noexcept = default;
82 
basic_wrapper(basic_wrapper const & other)83       basic_wrapper(basic_wrapper const &other)
84       {
85         *this = other;
86       }
87 
basic_wrapper(basic_wrapper && other)88       basic_wrapper(basic_wrapper &&other) noexcept
89       {
90         *this = std::move(other);
91       }
92 
c_ptr() const93       native_t *c_ptr() const
94       {
95         if(!object)
96           throw std::runtime_error("Tried to access empty object");
97         return object;
98       }
99 
has_object() const100       bool has_object() const
101       {
102         return object;
103       }
104 
operator bool() const105       operator bool() const
106       {
107         return has_object();
108       }
109 
operator native_t*() const110       operator native_t*() const
111       {
112         return c_ptr();
113       }
114 
operator =(const basic_wrapper & right)115       basic_wrapper& operator=(const basic_wrapper &right)
116       {
117         // Check for self-assignment
118         if(this == &right)
119           return *this;
120         object = right.object;
121         return *this;
122       }
123 
operator =(basic_wrapper && right)124       basic_wrapper& operator=(basic_wrapper &&right) noexcept
125       {
126         std::swap(object, right.object);
127         return *this;
128       }
129 
operator ==(const basic_wrapper & right) const130       bool operator==(const basic_wrapper &right) const
131       {
132         return object == right.object;
133       }
134 
operator !=(const basic_wrapper & right) const135       bool operator!=(const basic_wrapper &right) const
136       {
137         return !(*this == right); // Reuse equals operator
138       }
139     };
140 
141     /** \brief Refcounted wrapper for C objects
142      *
143      * This is by default copyable. If this is not desired, delete the
144      * copy constructor and copy assignment operator in derived classes.
145      */
146     template<typename native_t>
147     class refcounted_wrapper
148     {
149     private:
150       std::shared_ptr<native_t> object;
151 
152     protected:
refcounted_wrapper(std::shared_ptr<native_t> object)153       refcounted_wrapper(std::shared_ptr<native_t> object)
154         : object{std::move(object)}
155       {
156       }
157 
ref_ptr() const158       std::shared_ptr<native_t> ref_ptr() const
159       {
160         return object;
161       }
162 
163     public:
164       refcounted_wrapper() = default;
165       ~refcounted_wrapper() noexcept = default;
166 
refcounted_wrapper(refcounted_wrapper const & other)167       refcounted_wrapper(refcounted_wrapper const &other)
168       {
169         *this = other;
170       }
171 
refcounted_wrapper(refcounted_wrapper && other)172       refcounted_wrapper(refcounted_wrapper &&other) noexcept
173       {
174         *this = std::move(other);
175       }
176 
c_ptr() const177       native_t *c_ptr() const
178       {
179         if(!object)
180           throw std::runtime_error("Tried to access empty object");
181         return object.get();
182       }
183 
has_object() const184       bool has_object() const
185       {
186         return !!object;
187       }
188 
operator bool() const189       operator bool() const
190       {
191         return has_object();
192       }
193 
operator native_t*() const194       operator native_t*() const
195       {
196         return c_ptr();
197       }
198 
operator =(const refcounted_wrapper & right)199       refcounted_wrapper& operator=(const refcounted_wrapper &right)
200       {
201         // Check for self-assignment
202         if(this == &right)
203           return *this;
204         object = right.object;
205         return *this;
206       }
207 
operator =(refcounted_wrapper && right)208       refcounted_wrapper& operator=(refcounted_wrapper &&right) noexcept
209       {
210         std::swap(object, right.object);
211         return *this;
212       }
213 
operator ==(const refcounted_wrapper & right) const214       bool operator==(const refcounted_wrapper &right) const
215       {
216         return object == right.object;
217       }
218 
operator !=(const refcounted_wrapper & right) const219       bool operator!=(const refcounted_wrapper &right) const
220       {
221         return !(*this == right); // Reuse equals operator
222       }
223     };
224 
225     class any
226     {
227     private:
228       class base
229       {
230       public:
231         base() = default;
232         base(const base&) = default;
233         base(base&&) noexcept = default;
234         base& operator=(const base&) = default;
235         base& operator=(base&&) noexcept = default;
236         virtual ~base() noexcept = default;
237         virtual const std::type_info &type_info() const = 0;
238         virtual base *clone() const = 0;
239       };
240 
241       template <typename T>
242       class derived : public base
243       {
244       private:
245         T val;
246         friend class any;
247 
248       public:
derived(T t)249         derived(T t)
250           : val(std::move(t)) { }
251 
type_info() const252         const std::type_info &type_info() const override
253         {
254           return typeid(T);
255         }
256 
clone() const257         base *clone() const override
258         {
259           return new derived<T>(val);
260         }
261       };
262 
263       base *val = nullptr;
264 
265     public:
266       any() = default;
267 
any(const any & a)268       any(const any &a)
269         : val(a.val ? a.val->clone() : nullptr) { }
270 
any(any && a)271       any(any &&a) noexcept
272       {
273         operator=(std::move(a));
274       }
275 
276       template <typename T>
any(const T & t)277       any(const T &t)
278         : val(new derived<T>(t)) { }
279 
~any()280       ~any() noexcept
281       {
282         delete val;
283       }
284 
operator =(const any & a)285       any &operator=(const any &a)
286       {
287         if (&a != this)
288         {
289           delete val;
290           val = a.val ? a.val->clone() : nullptr;
291         }
292         return *this;
293       }
294 
operator =(any && a)295       any &operator=(any &&a) noexcept
296       {
297         std::swap(val, a.val);
298         return *this;
299       }
300 
301       template <typename T>
operator =(const T & t)302       any &operator=(const T &t)
303       {
304         if(val && typeid(T) == val->type_info())
305           static_cast<derived<T>*>(val)->val = t;
306         else
307           {
308             delete val;
309             val = new derived<T>(t);
310           }
311         return *this;
312       }
313 
314       template <typename T>
get()315       T &get()
316       {
317         if(val && typeid(T) == val->type_info())
318           return static_cast<derived<T>*>(val)->val;
319         throw std::bad_cast();
320       }
321 
322       template <typename T>
get() const323       const T &get() const
324       {
325         if(val && typeid(T) == val->type_info())
326           return static_cast<derived<T>*>(val)->val;
327         throw std::bad_cast();
328       }
329     };
330 
331     template<unsigned int size, int id = 0>
332     class bitfield
333     {
334       uint32_t v = 0;
335       static const uint32_t mask = (1 << size) - 1;
336 
337     public:
bitfield(const uint32_t value=0)338       explicit bitfield(const uint32_t value = 0)
339         : v(value)
340       {
341       }
342 
operator uint32_t() const343       explicit operator uint32_t() const
344       {
345         return v;
346       }
347 
operator bool() const348       operator bool() const
349       {
350         return v;
351       }
352 
bitfield(const bitfield<size,id> & b)353       bitfield(const bitfield<size, id> &b)
354       {
355         operator=(b);
356       }
357 
358       bitfield(bitfield<size, id>&&) noexcept = default;
359 
360       ~bitfield() noexcept = default;
361 
operator ==(const bitfield<size,id> & b)362       bool operator==(const bitfield<size, id> &b)
363       {
364         return v == b.v;
365       }
366 
operator !=(const bitfield<size,id> & b)367       bool operator!=(const bitfield<size, id> &b)
368       {
369         return !operator==(b);
370       }
371 
operator =(const bitfield<size,id> & b)372       bitfield<size, id> &operator=(const bitfield<size, id> &b)
373       {
374         // Check for self-assignment
375         if(this != &b)
376           v = static_cast<uint32_t>(b);
377         return *this;
378       }
379 
380       bitfield<size, id> &operator=(bitfield<size, id> &&) noexcept = default;
381 
operator |(const bitfield<size,id> & b) const382       bitfield<size, id> operator|(const bitfield<size, id> &b) const
383       {
384         return bitfield<size, id>(v | static_cast<uint32_t>(b));
385       }
386 
operator &(const bitfield<size,id> & b) const387       bitfield<size, id> operator&(const bitfield<size, id> &b) const
388       {
389         return bitfield<size, id>(v & static_cast<uint32_t>(b));
390       }
391 
operator ^(const bitfield<size,id> & b) const392       bitfield<size, id> operator^(const bitfield<size, id> &b) const
393       {
394         return bitfield<size, id>((v ^ static_cast<uint32_t>(b)) & mask);
395       }
396 
operator ~() const397       bitfield<size, id> operator~() const
398       {
399         return bitfield<size, id>(~v & mask);
400       }
401 
operator |=(const bitfield<size,id> & b)402       bitfield<size, id> &operator|=(const bitfield<size, id> &b)
403       {
404         operator=(*this | b);
405         return *this;
406       }
407 
operator &=(const bitfield<size,id> & b)408       bitfield<size, id> &operator&=(const bitfield<size, id> &b)
409       {
410         operator=(*this & b);
411         return *this;
412       }
413 
operator ^=(const bitfield<size,id> & b)414       bitfield<size, id> &operator^=(const bitfield<size, id> &b)
415       {
416         operator=(*this ^ b);
417         return *this;
418       }
419     };
420 
421     class argument_t
422     {
423     private:
424       wl_argument argument = { .i = 0 };
425       bool is_array{false};
426 
427       // Uninitialized argument - only for internal use
428       argument_t() = default;
429     public:
430 
431       argument_t(const argument_t &arg);
432       argument_t(argument_t &&) noexcept = default;
433       argument_t &operator=(const argument_t &arg);
434       argument_t &operator=(argument_t&&) noexcept = default;
435       ~argument_t() noexcept;
436 
437       // handles integers
438       argument_t(uint32_t i);
439       argument_t(int32_t i);
440 
441       // handles wl_fixed_t
442       argument_t(double f);
443 
444       // handles strings
445       argument_t(const std::string &s);
446 
447       // handles objects
448       argument_t(wl_object *o);
449 
450       // handles arrays
451       argument_t(const array_t& a);
452 
453       // handles null objects, for example for new-id arguments
454       argument_t(std::nullptr_t);
455 
456       // handles file descriptors (have same type as signed integers, so extra function)
457       static argument_t fd(int fileno);
458 
459       /**
460        * Get the contained wl_argument.
461        */
462       wl_argument get_c_argument() const;
463     };
464   }
465 
466   class array_t
467   {
468   private:
469     wl_array a = { 0, 0, nullptr };
470 
471     array_t(wl_array *arr);
472     void get(wl_array *arr) const;
473 
474     friend class proxy_t;
475     friend class detail::argument_t;
476 
477   public:
478     array_t();
479     array_t(const array_t &arr);
480     array_t(array_t &&arr) noexcept;
481 
array_t(const std::vector<T> & v)482     template <typename T> array_t(const std::vector<T> &v)
483     {
484       wl_array_init(&a);
485       wl_array_add(&a, v.size()*sizeof(T));
486       T *p = nullptr;
487       unsigned int c = 0;
488       wl_array_for_each_cpp(p, &a)
489         *p = v.at(c++);
490     }
491 
492     ~array_t();
493     array_t &operator=(const array_t &arr);
494     array_t &operator=(array_t &&arr) noexcept;
495 
operator =(const std::vector<T> & v)496     template <typename T> array_t &operator=(const std::vector<T> &v)
497     {
498       wl_array_release(&a);
499       wl_array_init(&a);
500       wl_array_add(&a, v.size()*sizeof(T));
501       T *p = nullptr;
502       unsigned int c = 0;
503       wl_array_for_each_cpp(p, &a)
504         *p = v.at(c++);
505       return *this;
506     }
507 
operator std::vector<T>() const508     template <typename T> operator std::vector<T>() const
509     {
510       std::vector<T> v;
511       T *p = nullptr;
512       wl_array_for_each_cpp(p, &a)
513         v.push_back(*p);
514       return v;
515     }
516   };
517 }
518 
519 #endif
520