initial commit
[liquidmodel] / libs / anim / dynarr.c
1 /*
2 libanim - hierarchical keyframe animation library
3 Copyright (C) 2012-2014 John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published
7 by the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "dynarr.h"
23
24 /* The array descriptor keeps auxilliary information needed to manipulate
25  * the dynamic array. It's allocated adjacent to the array buffer.
26  */
27 struct arrdesc {
28         int nelem, szelem;
29         int max_elem;
30         int bufsz;      /* not including the descriptor */
31 };
32
33 #define DESC(x)         ((struct arrdesc*)((char*)(x) - sizeof(struct arrdesc)))
34
35 void *anm_dynarr_alloc(int elem, int szelem)
36 {
37         struct arrdesc *desc;
38
39         if(!(desc = malloc(elem * szelem + sizeof *desc))) {
40                 return 0;
41         }
42         desc->nelem = desc->max_elem = elem;
43         desc->szelem = szelem;
44         desc->bufsz = elem * szelem;
45         return (char*)desc + sizeof *desc;
46 }
47
48 void anm_dynarr_free(void *da)
49 {
50         if(da) {
51                 free(DESC(da));
52         }
53 }
54
55 void *anm_dynarr_resize(void *da, int elem)
56 {
57         int newsz;
58         void *tmp;
59         struct arrdesc *desc;
60
61         if(!da) return 0;
62         desc = DESC(da);
63
64         newsz = desc->szelem * elem;
65
66         if(!(tmp = realloc(desc, newsz + sizeof *desc))) {
67                 return 0;
68         }
69         desc = tmp;
70
71         desc->nelem = desc->max_elem = elem;
72         desc->bufsz = newsz;
73         return (char*)desc + sizeof *desc;
74 }
75
76 int anm_dynarr_empty(void *da)
77 {
78         return DESC(da)->nelem ? 0 : 1;
79 }
80
81 int anm_dynarr_size(void *da)
82 {
83         return DESC(da)->nelem;
84 }
85
86
87 /* stack semantics */
88 void *anm_dynarr_push(void *da, void *item)
89 {
90         struct arrdesc *desc;
91         int nelem;
92
93         desc = DESC(da);
94         nelem = desc->nelem;
95
96         if(nelem >= desc->max_elem) {
97                 /* need to resize */
98                 struct arrdesc *tmp;
99                 int newsz = desc->max_elem ? desc->max_elem * 2 : 1;
100
101                 if(!(tmp = anm_dynarr_resize(da, newsz))) {
102                         fprintf(stderr, "failed to resize\n");
103                         return da;
104                 }
105                 da = tmp;
106                 desc = DESC(da);
107                 desc->nelem = nelem;
108         }
109
110         memcpy((char*)da + desc->nelem++ * desc->szelem, item, desc->szelem);
111         return da;
112 }
113
114 void *anm_dynarr_pop(void *da)
115 {
116         struct arrdesc *desc;
117         int nelem;
118
119         desc = DESC(da);
120         nelem = desc->nelem;
121
122         if(!nelem) return da;
123
124         if(nelem <= desc->max_elem / 3) {
125                 /* reclaim space */
126                 struct arrdesc *tmp;
127                 int newsz = desc->max_elem / 2;
128
129                 if(!(tmp = anm_dynarr_resize(da, newsz))) {
130                         fprintf(stderr, "failed to resize\n");
131                         return da;
132                 }
133                 da = tmp;
134                 desc = DESC(da);
135                 desc->nelem = nelem;
136         }
137         desc->nelem--;
138
139         return da;
140 }