VLC 4.0.0-dev
vlc_cxx_helpers.hpp
Go to the documentation of this file.
1/*****************************************************************************
2 * vlc_cxx_helpers.hpp: C++ helpers
3 *****************************************************************************
4 * Copyright (C) 1998-2018 VLC authors and VideoLAN
5 *
6 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
22
23#ifndef VLC_CXX_HELPERS_HPP
24#define VLC_CXX_HELPERS_HPP
25
26/******************************************************************************
27 * C++ memory management helpers
28 ******************************************************************************/
29
30#ifdef __cplusplus
31
32#include <memory>
33#include <utility>
34#include <type_traits>
35#include <string>
36#include <stdexcept>
37
38#ifdef VLC_THREADS_H_
39// Ensure we can use vlc_sem_wait_i11e. We can't declare different versions
40// of the semaphore helper based on vlc_interrupt inclusion, as it would
41// violate ODR
42# include <vlc_interrupt.h>
43#endif
44
45namespace vlc
46{
47
48namespace
49{
50// This helpers need static linkage to avoid their signature to change when
51// building as C++17 (noexcept becomes part of the function signature stating there)
52
53// Wraps a pointer with a custom releaser
54// ex: auto ptr = vlc_wrap_cptr( input_item, &input_item_Release );
55
56///
57/// Wraps a C pointer into a std::unique_ptr
58///
59/// This will convert a C pointer of type T to a std::unique_ptr<T, R> where
60/// T is the pointee type, and R is an arbitrary releaser type.
61///
62/// ptr will be automatically released by calling r( ptr ) when falling out of
63/// scope (whether by returning of by throwing an exception
64///
65/// @param ptr a C pointer
66/// @param r An instance of a Callable type, that will be invoked with ptr
67/// as its first and only parameter.
68template <typename T, typename Releaser>
69inline auto wrap_cptr( T* ptr, Releaser&& r ) noexcept
70 -> std::unique_ptr<T, typename std::decay<decltype( r )>::type>
71{
72 return std::unique_ptr<T, typename std::decay<decltype( r )>::type>{
73 ptr, std::forward<Releaser>( r )
74 };
75}
76
77///
78/// Wraps a C pointer into a std::unique_ptr
79///
80/// This will convert a C pointer to an array of type T to a
81/// std::unique_ptr<T[], R> where T is the pointee type, and R is an arbitrary
82/// releaser type.
83///
84/// ptr will be automatically released by calling r( ptr ) when falling out of
85/// scope (whether by returning of by throwing an exception
86///
87/// This function is equivalent to wrap_cptr, except that the returned
88/// unique_ptr provides an operator[] for array access instead of operator* and
89/// operator->
90///
91/// @param ptr a C pointer
92/// @param r An instance of a Callable type, that will be invoked with ptr
93/// as its first and only parameter.
94template <typename T, typename Releaser>
95inline auto wrap_carray( T* ptr, Releaser&& r ) noexcept
96 -> std::unique_ptr<T[], typename std::decay<decltype( r )>::type>
97{
98 return std::unique_ptr<T[], typename std::decay<decltype( r )>::type>{
99 ptr, std::forward<Releaser>( r )
100 };
101}
102
103///
104/// Wraps a C pointer into a std::unique_ptr
105///
106/// This is a convenience wrapper that will use free() as its releaser
107///
108template <typename T>
109inline std::unique_ptr<T, void (*)(void*)> wrap_cptr( T* ptr ) noexcept
110{
111 return wrap_cptr( ptr, &free );
112}
113
114///
115/// Wraps a C pointer into a std::unique_ptr
116///
117/// This is a convenience wrapper that will use free() as its releaser
118///
119template <typename T>
120inline std::unique_ptr<T[], void (*)(void*)> wrap_carray( T* ptr ) noexcept
121{
122 return wrap_carray( ptr, &free );
123}
124
125} // anonymous namespace
126
127///
128/// Wraps a C shared resource having associated Hold() and Release() functions
129//
130/// This is a RAII wrapper for C shared resources (which are manually managed by
131/// calling explicitly their Hold() and Release() functions).
132///
133/// The Hold() and Release() functions must accept exactly one parameter having
134/// type T* (the raw pointer type). Their return type is irrelevant.
135///
136/// To create a new shared resource wrapper type for my_type_t, simply declare:
137///
138/// using MyTypePtr =
139/// vlc_shared_data_ptr_type(my_type_t, my_type_Hold, my_type_Release);
140///
141/// Then use it to wrap a raw C pointer:
142///
143/// my_type_t *raw_ptr = /* ... */;
144/// MyTypePtr ptr(raw_ptr);
145
146// In C++17, the template declaration could be replaced by:
147// template<typename T, auto HOLD, auto RELEASE>
148template <typename T, typename H, typename R, H HOLD, R RELEASE>
149class vlc_shared_data_ptr {
150 T *ptr = nullptr;
151
152public:
153 /* default implicit constructor */
154 vlc_shared_data_ptr() = default;
155
156 /**
157 * Wrap a shared resource.
158 *
159 * If the pointer is not nullptr, and hold is true, then the resource is
160 * hold (the caller shared ownership is preserved).
161 * If hold is false, then the caller transfers the ownership to this
162 * wrapper.
163 *
164 * \param ptr the raw pointer (can be nullptr)
165 * \param hold whether the resource must be hold
166 */
167 explicit vlc_shared_data_ptr(T *ptr, bool hold = true)
168 : ptr(ptr)
169 {
170 if (ptr && hold)
171 HOLD(ptr);
172 }
173
174 vlc_shared_data_ptr(std::nullptr_t)
175 : ptr(nullptr)
176 {
177 }
178
179 vlc_shared_data_ptr(const vlc_shared_data_ptr &other)
180 : vlc_shared_data_ptr(other.ptr) {}
181
182 vlc_shared_data_ptr(vlc_shared_data_ptr &&other) noexcept
183 : ptr(other.ptr)
184 {
185 other.ptr = nullptr;
186 }
187
188 ~vlc_shared_data_ptr()
189 {
190 if (ptr)
191 RELEASE(ptr);
192 }
193
194 vlc_shared_data_ptr &operator=(const vlc_shared_data_ptr &other)
195 {
196 reset(other.ptr, true);
197 return *this;
198 }
199
200 vlc_shared_data_ptr &operator=(vlc_shared_data_ptr &&other) noexcept
201 {
202 reset(other.ptr, false);
203 other.ptr = nullptr;
204 return *this;
205 }
206
207 bool operator==(const vlc_shared_data_ptr &other) const
208 {
209 return ptr == other.ptr;
210 }
211
212 bool operator==(std::nullptr_t) const noexcept
213 {
214 return ptr == nullptr;
215 }
216
217 bool operator!=(const vlc_shared_data_ptr &other) const
218 {
219 return !(*this == other);
220 }
221
222 bool operator!=(std::nullptr_t) const noexcept
223 {
224 return ptr != nullptr;
225 }
226
227 explicit operator bool() const
228 {
229 return ptr;
230 }
231
232 T &operator*() const
233 {
234 return *ptr;
235 }
236
237 T *operator->() const
238 {
239 return ptr;
240 }
241
242 T *get() const
243 {
244 return ptr;
245 }
246
247 /**
248 * Reset the shared resource.
249 *
250 * ptr.reset(rawptr, hold);
251 *
252 * is semantically equivalent to:
253 *
254 * ptr = vlc_shared_data_ptr<...>(rawptr, hold);
255 *
256 * If the pointer is not nullptr, and hold is true, then the resource is
257 * hold (the caller shared ownership is preserved).
258 * If hold is false, then the caller transfers the ownership to this
259 * wrapper.
260 *
261 * \param ptr the raw pointer (can be nullptr)
262 * \param hold whether the resource must be hold
263 */
264 void reset(T *newptr = nullptr, bool hold = true)
265 {
266 if (newptr && hold)
267 HOLD(newptr);
268 if (ptr)
269 RELEASE(ptr);
270 ptr = newptr;
271 }
272};
273
274// useful due to the unnecessarily complex template declaration before C++17
275#define vlc_shared_data_ptr_type(type, hold, release) \
276 ::vlc::vlc_shared_data_ptr<type, decltype(&hold), decltype(&release), \
277 &hold, &release>
278
279#ifdef VLC_THREADS_H_
280
281namespace threads
282{
283
284class mutex
285{
286public:
287 mutex() noexcept
288 {
289 vlc_mutex_init( &m_mutex );
290 }
291
292 mutex( const mutex& ) = delete;
293 mutex& operator=( const mutex& ) = delete;
294 mutex( mutex&& ) = delete;
295 mutex& operator=( mutex&& ) = delete;
296
297 void lock() noexcept
298 {
299 vlc_mutex_lock( &m_mutex );
300 }
301 void unlock() noexcept
302 {
303 vlc_mutex_unlock( &m_mutex );
304 }
305
306private:
307 vlc_mutex_t m_mutex;
308 friend class condition_variable;
309 friend class mutex_locker;
310};
311
312class condition_variable
313{
314public:
315 condition_variable() noexcept
316 {
317 vlc_cond_init( &m_cond );
318 }
319 void signal() noexcept
320 {
321 vlc_cond_signal( &m_cond );
322 }
323 void broadcast() noexcept
324 {
325 vlc_cond_broadcast( &m_cond );
326 }
327 void wait( mutex& mutex ) noexcept
328 {
329 vlc_cond_wait( &m_cond, &mutex.m_mutex );
330 }
331 int timedwait( mutex& mutex, vlc_tick_t deadline ) noexcept
332 {
333 return vlc_cond_timedwait( &m_cond, &mutex.m_mutex, deadline );
334 }
335
336private:
337 vlc_cond_t m_cond;
338};
339
340class mutex_locker
341{
342public:
343 mutex_locker( vlc_mutex_t* m ) noexcept
344 : m_mutex( m )
345 {
346 vlc_mutex_lock( m_mutex );
347 }
348 mutex_locker( mutex& m ) noexcept
349 : mutex_locker( &m.m_mutex )
350 {
351 }
352 ~mutex_locker()
353 {
354 vlc_mutex_unlock( m_mutex );
355 }
356 mutex_locker( const mutex_locker& ) = delete;
357 mutex_locker& operator=( const mutex_locker& ) = delete;
358 mutex_locker( mutex_locker&& ) = delete;
359 mutex_locker& operator=( mutex_locker&& ) = delete;
360
361private:
362 vlc_mutex_t* m_mutex;
363};
364
365class semaphore
366{
367public:
368 semaphore() noexcept
369 {
370 vlc_sem_init( &m_sem, 0 );
371 }
372 semaphore( unsigned int count ) noexcept
373 {
374 vlc_sem_init( &m_sem, count );
375 }
376 ~semaphore()
377 {
378 }
379
380 semaphore( const semaphore& ) = delete;
381 semaphore& operator=( const semaphore& ) = delete;
382 semaphore( semaphore&& ) = delete;
383 semaphore& operator=( semaphore&& ) = delete;
384
385 int post() noexcept
386 {
387 return vlc_sem_post( &m_sem );
388 }
389 void wait() noexcept
390 {
391 vlc_sem_wait( &m_sem );
392 }
393
394 int wait_i11e() noexcept
395 {
396 return vlc_sem_wait_i11e( &m_sem );
397 }
398
399private:
400 vlc_sem_t m_sem;
401};
402
403}
404
405#endif // VLC_THREADS_H_
406
407#ifdef VLC_URL_H
408
409class url : public vlc_url_t
410{
411public:
412 class invalid : public std::runtime_error
413 {
414 public:
415 explicit invalid( const char* url )
416 : std::runtime_error( std::string{ "Invalid url: " } + url )
417 {
418 }
419 };
420
421 url()
422 {
423 psz_buffer = nullptr;
424 psz_pathbuffer = nullptr;
425 psz_host = nullptr;
426 }
427
428 explicit url( const char* str )
429 {
430 if ( vlc_UrlParse( this, str ) )
431 {
432 vlc_UrlClean( this );
433 throw invalid( str );
434 }
435 }
436
437 explicit url( const std::string& str )
438 : url( str.c_str() )
439 {
440 }
441
442 ~url()
443 {
444 vlc_UrlClean(this);
445 }
446
447 url( const url& ) = delete;
448 url& operator=( const url& ) = delete;
449
450 url( url&& u ) noexcept
451 : vlc_url_t( u )
452 {
453 u.psz_buffer = nullptr;
454 u.psz_pathbuffer = nullptr;
455 u.psz_host = nullptr;
456 }
457
458 url& operator=( url&& u ) noexcept
459 {
460 vlc_UrlClean( this );
461 *(static_cast<vlc_url_t*>( this )) = u;
462 u.psz_buffer = nullptr;
463 u.psz_pathbuffer = nullptr;
464 u.psz_host = nullptr;
465 return *this;
466 }
467};
468
469#endif
470
471} // namespace vlc
472
473#endif
474
475#endif // VLC_CXX_HELPERS_HPP
size_t count
Definition: core.c:403
void vlc_cond_signal(vlc_cond_t *cond)
Wakes up one thread waiting on a condition variable.
Definition: threads.c:204
int vlc_cond_timedwait(vlc_cond_t *cond, vlc_mutex_t *mutex, vlc_tick_t deadline)
Waits on a condition variable up to a certain date.
Definition: threads.c:303
void vlc_cond_broadcast(vlc_cond_t *cond)
Wakes up all threads waiting on a condition variable.
Definition: threads.c:231
void vlc_cond_wait(vlc_cond_t *cond, vlc_mutex_t *mutex)
Waits on a condition variable.
Definition: threads.c:291
void vlc_cond_init(vlc_cond_t *cond)
Initializes a condition variable.
Definition: threads.c:185
int vlc_sem_wait_i11e(vlc_sem_t *sem)
Interruptible variant of vlc_sem_wait().
Definition: interrupt.c:198
void vlc_mutex_unlock(vlc_mutex_t *mtx)
Releases a mutex.
Definition: threads.c:160
void vlc_mutex_init(vlc_mutex_t *mtx)
Initializes a fast mutex.
Definition: threads.c:74
void vlc_mutex_lock(vlc_mutex_t *mtx)
Acquires a mutex.
Definition: threads.c:106
void vlc_sem_wait(vlc_sem_t *sem)
Waits on a semaphore.
Definition: threads.c:355
int vlc_sem_post(vlc_sem_t *sem)
Increments the value of a semaphore.
Definition: threads.c:339
void vlc_sem_init(vlc_sem_t *sem, unsigned value)
Initializes a semaphore.
Definition: threads.c:334
int vlc_UrlParse(vlc_url_t *url, const char *str)
Parses an URI or IRI.
Definition: url.c:581
vlc_mutex_t lock
Definition: rand.c:33
Condition variable.
Definition: vlc_threads.h:322
Mutex.
Definition: vlc_threads.h:195
Semaphore.
Definition: vlc_threads.h:422
Definition: vlc_url.h:146
char * psz_buffer
Definition: vlc_url.h:156
void vlc_UrlClean(vlc_url_t *restrict url)
Definition: url.c:621
struct vlc_url_t vlc_url_t
Definition: vlc_common.h:450
This file declares interruptible sleep functions.
int64_t vlc_tick_t
High precision date or time interval.
Definition: vlc_tick.h:45