New test.
[mono.git] / eglib / src / garray.c
1 /*
2  * Arrays
3  *
4  * Author:
5  *   Chris Toshok (toshok@novell.com)
6  *
7  * (C) 2006 Novell, Inc.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining
10  * a copy of this software and associated documentation files (the
11  * "Software"), to deal in the Software without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  */
28  
29 #define _GNU_SOURCE
30 #include <stdlib.h>
31 #include <glib.h>
32
33 #define INITIAL_CAPACITY 16
34
35 #define element_offset(p,i) ((p)->array.data + (i) * (p)->element_size)
36 #define element_length(p,i) ((i) * (p)->element_size)
37
38 typedef struct {
39   GArray array;
40   gboolean clear_;
41   gboolean element_size;
42   gboolean zero_terminated;
43   gint capacity;
44 } GArrayPriv;
45
46 static void
47 ensure_capacity (GArrayPriv *priv,
48                  int capacity)
49 {
50         int new_capacity = MAX (priv->capacity, INITIAL_CAPACITY);
51
52         if (capacity < priv->capacity)
53                 return;
54
55         while (new_capacity < capacity) {
56                 new_capacity <<= 1;
57         }
58         capacity = new_capacity;
59         priv->array.data = (gchar*)g_realloc (priv->array.data, element_length (priv, capacity));
60
61         if (priv->clear_) {
62                 memset (element_offset (priv, priv->capacity),
63                         0,
64                         element_length (priv, capacity - priv->capacity));
65         }
66         priv->capacity = capacity;
67 }
68
69 GArray *
70 g_array_new (gboolean zero_terminated,
71              gboolean clear_,
72              guint element_size)
73 {
74         GArrayPriv *rv = g_new0 (GArrayPriv, 1);
75         rv->zero_terminated = zero_terminated;
76         rv->clear_ = clear_;
77         rv->element_size = element_size;
78
79         ensure_capacity (rv, INITIAL_CAPACITY);
80
81         return (GArray*)rv;
82 }
83
84 gchar*
85 g_array_free (GArray *array,
86               gboolean free_segment)
87 {
88         gchar* rv = NULL;
89         if (free_segment)
90                 g_free (array->data);
91         else
92                 rv = array->data;
93
94         g_free (array);
95
96         return rv;
97 }
98
99 GArray *
100 g_array_append_vals (GArray *array,
101                      gconstpointer data,
102                      guint len)
103 {
104         GArrayPriv *priv = (GArrayPriv*)array;
105
106         ensure_capacity (priv, priv->array.len + len + (priv->zero_terminated ? 1 : 0));
107   
108         memmove (element_offset (priv, priv->array.len),
109                  data,
110                  element_length (priv, len));
111
112         priv->array.len += len;
113
114         if (priv->zero_terminated) {
115                 memset (element_offset (priv, priv->array.len),
116                         0,
117                         priv->element_size);
118         }
119
120         return array;
121 }
122
123 GArray*
124 g_array_insert_vals (GArray *array,
125                      guint index_,
126                      gconstpointer data,
127                      guint len)
128 {
129         GArrayPriv *priv = (GArrayPriv*)array;
130
131         ensure_capacity (priv, array->len + len + (priv->zero_terminated ? 1 : 0));
132   
133         /* first move the existing elements out of the way */
134         memmove (element_offset (priv, index_ + len),
135                  element_offset (priv, index_),
136                  element_length (priv, len - index_));
137
138         /* then copy the new elements into the array */
139         memmove (element_offset (priv, array->len),
140                  data,
141                  element_length (priv, index_));
142
143         array->len += len;
144
145         if (priv->zero_terminated) {
146                 memset (element_offset (priv, priv->array.len),
147                         0,
148                         priv->element_size);
149         }
150
151         return array;
152 }
153
154 GArray*
155 g_array_remove_index (GArray *array,
156                       guint index_)
157 {
158         GArrayPriv *priv = (GArrayPriv*)array;
159
160         memmove (element_offset (priv, index_),
161                  element_offset (priv, index_ + 1),
162                  element_length (priv, array->len - index_));
163
164         array->len --;
165
166         if (priv->zero_terminated) {
167                 memset (element_offset (priv, priv->array.len),
168                         0,
169                         priv->element_size);
170         }
171
172         return array;
173 }