LGPL
[vlc.git] / src / extras / tdestroy.c
1 /**
2  * @file tdestroy.c
3  * @brief replacement for GNU tdestroy()
4  */
5 /*****************************************************************************
6  * Copyright (C) 2009 RĂ©mi Denis-Courmont
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 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #if defined(HAVE_SEARCH_H) && !defined(HAVE_TDESTROY)
28
29 #include <stdlib.h>
30 #include <assert.h>
31
32 #include <vlc_common.h>
33 #include <search.h>
34
35 static struct
36 {
37     const void **tab;
38     size_t count;
39     vlc_mutex_t lock;
40 } list = { NULL, 0, VLC_STATIC_MUTEX };
41
42 static void list_nodes (const void *node, const VISIT which, const int depth)
43 {
44     (void) depth;
45
46     if (which != postorder && which != leaf)
47         return;
48
49     const void **tab = realloc (list.tab, sizeof (*tab) * (list.count + 1));
50     if (unlikely(tab == NULL))
51         abort ();
52
53     tab[list.count] = *(const void **)node;
54     list.tab = tab;
55     list.count++;
56 }
57
58 static struct
59 {
60     const void *node;
61     vlc_mutex_t lock;
62 } smallest = { NULL, VLC_STATIC_MUTEX };
63
64 static int cmp_smallest (const void *a, const void *b)
65 {
66     if (a == b)
67         return 0;
68     if (a == smallest.node)
69         return -1;
70     if (likely(b == smallest.node))
71         return +1;
72     abort ();
73 }
74
75 void vlc_tdestroy (void *root, void (*freenode) (void *))
76 {
77     const void **tab;
78     size_t count;
79
80     assert (freenode != NULL);
81
82     /* Enumerate nodes in order */
83     vlc_mutex_lock (&list.lock);
84     assert (list.count == 0);
85     twalk (root, list_nodes);
86     tab = list.tab;
87     count = list.count;
88     list.tab = NULL;
89     list.count = 0;
90     vlc_mutex_unlock (&list.lock);
91
92     /* Destroy the tree */
93     vlc_mutex_lock (&smallest.lock);
94     for (size_t i = 0; i < count; i++)
95     {
96          smallest.node = tab[i];
97          if (tdelete (smallest.node, &root, cmp_smallest) == NULL)
98              abort ();
99     }
100     vlc_mutex_unlock (&smallest.lock);
101     assert (root == NULL);
102
103     /* Destroy the nodes */
104     for (size_t i = 0; i < count; i++)
105          freenode ((void *)(tab[i]));
106     free (tab);
107 }
108
109 #endif