Coverage Report

Created: 2025-12-31 07:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/include/vlc_cxx_helpers.hpp
Line
Count
Source
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
#if defined(__cplusplus) || defined(DOC)
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
45
namespace vlc
46
{
47
48
namespace
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 or 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.
68
template <typename T, typename Releaser>
69
inline auto wrap_cptr( T* ptr, Releaser&& r ) noexcept
70
    -> std::unique_ptr<T, typename std::decay<decltype( r )>::type>
71
17
{
72
17
    return std::unique_ptr<T, typename std::decay<decltype( r )>::type>{
73
17
                ptr, std::forward<Releaser>( r )
74
17
    };
75
17
}
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 or 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.
94
template <typename T, typename Releaser>
95
inline 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
///
108
template <typename T>
109
inline 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
///
119
template <typename T>
120
inline 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::vlc_shared_data_ptr<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
template <typename T, auto HOLD, auto RELEASE>
146
class vlc_shared_data_ptr {
147
    T *ptr = nullptr;
148
149
public:
150
    /* default implicit constructor */
151
    vlc_shared_data_ptr() = default;
152
153
    /**
154
     * Wrap a shared resource.
155
     *
156
     * If the pointer is not nullptr, and hold is true, then the resource is
157
     * hold (the caller shared ownership is preserved).
158
     * If hold is false, then the caller transfers the ownership to this
159
     * wrapper.
160
     *
161
     * \param ptr  the raw pointer (can be nullptr)
162
     * \param hold whether the resource must be hold
163
     */
164
    explicit vlc_shared_data_ptr(T *ptr, bool hold = true)
165
        : ptr(ptr)
166
    {
167
        if (ptr && hold)
168
            HOLD(ptr);
169
    }
170
171
    vlc_shared_data_ptr(std::nullptr_t)
172
        : ptr(nullptr)
173
    {
174
    }
175
176
    vlc_shared_data_ptr(const vlc_shared_data_ptr &other)
177
        : vlc_shared_data_ptr(other.ptr) {}
178
179
    vlc_shared_data_ptr(vlc_shared_data_ptr &&other) noexcept
180
        : ptr(other.ptr)
181
    {
182
        other.ptr = nullptr;
183
    }
184
185
    ~vlc_shared_data_ptr()
186
    {
187
        if (ptr)
188
            RELEASE(ptr);
189
    }
190
191
    vlc_shared_data_ptr &operator=(const vlc_shared_data_ptr &other)
192
    {
193
        reset(other.ptr, true);
194
        return *this;
195
    }
196
197
    vlc_shared_data_ptr &operator=(vlc_shared_data_ptr &&other) noexcept
198
    {
199
        reset(other.ptr, false);
200
        other.ptr = nullptr;
201
        return *this;
202
    }
203
204
    bool operator==(const vlc_shared_data_ptr &other) const
205
    {
206
        return ptr == other.ptr;
207
    }
208
209
    bool operator==(std::nullptr_t) const noexcept
210
    {
211
        return ptr == nullptr;
212
    }
213
214
    bool operator!=(const vlc_shared_data_ptr &other) const
215
    {
216
        return !(*this == other);
217
    }
218
219
    bool operator!=(std::nullptr_t) const noexcept
220
    {
221
        return ptr != nullptr;
222
    }
223
224
    explicit operator bool() const
225
    {
226
        return ptr;
227
    }
228
229
    T &operator*() const
230
    {
231
        return *ptr;
232
    }
233
234
    T *operator->() const
235
    {
236
        return ptr;
237
    }
238
239
    T *get() const
240
    {
241
        return ptr;
242
    }
243
244
    /**
245
     * Reset the shared resource.
246
     *
247
     *     ptr.reset(rawptr, hold);
248
     *
249
     * is semantically equivalent to:
250
     *
251
     *     ptr = vlc_shared_data_ptr<...>(rawptr, hold);
252
     *
253
     * If the pointer is not nullptr, and hold is true, then the resource is
254
     * hold (the caller shared ownership is preserved).
255
     * If hold is false, then the caller transfers the ownership to this
256
     * wrapper.
257
     *
258
     * \param newptr  the raw pointer (can be nullptr)
259
     * \param hold    whether the resource must be hold
260
     */
261
    void reset(T *newptr = nullptr, bool hold = true)
262
    {
263
        if (newptr && hold)
264
            HOLD(newptr);
265
        if (ptr)
266
            RELEASE(ptr);
267
        ptr = newptr;
268
    }
269
};
270
271
#if defined(VLC_THREADS_H_) || defined(DOC)
272
273
namespace threads
274
{
275
276
class mutex
277
{
278
public:
279
    mutex() noexcept
280
832
    {
281
832
        vlc_mutex_init( &m_mutex );
282
832
    }
283
284
    mutex( const mutex& ) = delete;
285
    mutex& operator=( const mutex& ) = delete;
286
    mutex( mutex&& ) = delete;
287
    mutex& operator=( mutex&& ) = delete;
288
289
    void lock() noexcept
290
26.3k
    {
291
26.3k
        vlc_mutex_lock( &m_mutex );
292
26.3k
    }
293
    void unlock() noexcept
294
26.3k
    {
295
26.3k
        vlc_mutex_unlock( &m_mutex );
296
26.3k
    }
297
298
private:
299
    vlc_mutex_t m_mutex;
300
    friend class condition_variable;
301
    friend class mutex_locker;
302
};
303
304
class condition_variable
305
{
306
public:
307
    condition_variable() noexcept
308
0
    {
309
0
        vlc_cond_init( &m_cond );
310
0
    }
311
    void signal() noexcept
312
0
    {
313
0
        vlc_cond_signal( &m_cond );
314
0
    }
315
    void broadcast() noexcept
316
0
    {
317
0
        vlc_cond_broadcast( &m_cond );
318
0
    }
319
    void wait( mutex& mutex ) noexcept
320
0
    {
321
0
        vlc_cond_wait( &m_cond, &mutex.m_mutex );
322
0
    }
323
    int timedwait( mutex& mutex, vlc_tick_t deadline ) noexcept
324
0
    {
325
0
        return vlc_cond_timedwait( &m_cond, &mutex.m_mutex, deadline );
326
0
    }
327
328
private:
329
    vlc_cond_t m_cond;
330
};
331
332
class mutex_locker
333
{
334
public:
335
    mutex_locker( vlc_mutex_t* m ) noexcept
336
        : m_mutex( m )
337
0
    {
338
0
        vlc_mutex_lock( m_mutex );
339
0
    }
340
    mutex_locker( mutex& m ) noexcept
341
        : mutex_locker( &m.m_mutex )
342
0
    {
343
0
    }
344
    ~mutex_locker()
345
0
    {
346
0
        vlc_mutex_unlock( m_mutex );
347
0
    }
348
    mutex_locker( const mutex_locker& ) = delete;
349
    mutex_locker& operator=( const mutex_locker& ) = delete;
350
    mutex_locker( mutex_locker&& ) = delete;
351
    mutex_locker& operator=( mutex_locker&& ) = delete;
352
353
private:
354
    vlc_mutex_t* m_mutex;
355
};
356
357
class semaphore
358
{
359
public:
360
    semaphore() noexcept
361
0
    {
362
0
        vlc_sem_init( &m_sem, 0 );
363
0
    }
364
    semaphore( unsigned int count ) noexcept
365
0
    {
366
0
        vlc_sem_init( &m_sem, count );
367
0
    }
368
    ~semaphore()
369
0
    {
370
0
    }
371
372
    semaphore( const semaphore& ) = delete;
373
    semaphore& operator=( const semaphore& ) = delete;
374
    semaphore( semaphore&& ) = delete;
375
    semaphore& operator=( semaphore&& ) = delete;
376
377
    int post() noexcept
378
0
    {
379
0
        return vlc_sem_post( &m_sem );
380
0
    }
381
    void wait() noexcept
382
0
    {
383
0
        vlc_sem_wait( &m_sem );
384
0
    }
385
386
    int wait_i11e() noexcept
387
0
    {
388
0
        return vlc_sem_wait_i11e( &m_sem );
389
0
    }
390
391
private:
392
    vlc_sem_t m_sem;
393
};
394
395
}
396
397
#endif // VLC_THREADS_H_
398
399
#ifdef VLC_URL_H
400
401
class url : public vlc_url_t
402
{
403
public:
404
    class invalid : public std::runtime_error
405
    {
406
    public:
407
        explicit invalid( const char* url )
408
            : std::runtime_error( std::string{ "Invalid url: " } + url )
409
        {
410
        }
411
    };
412
413
    url()
414
    {
415
        psz_buffer = nullptr;
416
        psz_pathbuffer = nullptr;
417
        psz_host = nullptr;
418
    }
419
420
    explicit url( const char* str )
421
    {
422
        if ( vlc_UrlParse( this, str ) )
423
        {
424
            vlc_UrlClean( this );
425
            throw invalid( str );
426
        }
427
    }
428
429
    explicit url( const std::string& str )
430
        : url( str.c_str() )
431
    {
432
    }
433
434
    ~url()
435
    {
436
        vlc_UrlClean(this);
437
    }
438
439
    url( const url& ) = delete;
440
    url& operator=( const url& ) = delete;
441
442
    url( url&& u ) noexcept
443
        : vlc_url_t( u )
444
    {
445
        u.psz_buffer = nullptr;
446
        u.psz_pathbuffer = nullptr;
447
        u.psz_host = nullptr;
448
    }
449
450
    url& operator=( url&& u ) noexcept
451
    {
452
        vlc_UrlClean( this );
453
        *(static_cast<vlc_url_t*>( this )) = u;
454
        u.psz_buffer = nullptr;
455
        u.psz_pathbuffer = nullptr;
456
        u.psz_host = nullptr;
457
        return *this;
458
    }
459
};
460
461
#endif
462
463
} // namespace vlc
464
465
#endif
466
467
#endif // VLC_CXX_HELPERS_HPP